from datetime import datetime, timedelta, timezone from decimal import Decimal from typing import TYPE_CHECKING, Any, Optional from unittest import mock import orjson import time_machine from django.utils.timezone import now as timezone_now from typing_extensions import override from corporate.lib.stripe import RealmBillingSession, add_months from corporate.models import ( Customer, CustomerPlan, LicenseLedger, get_current_plan_by_realm, get_customer_by_realm, ) from zerver.actions.invites import do_create_multiuse_invite_link from zerver.actions.realm_settings import do_change_realm_org_type, do_send_realm_reactivation_email from zerver.actions.user_settings import do_change_user_setting from zerver.lib.test_classes import ZulipTestCase from zerver.lib.test_helpers import reset_email_visibility_to_everyone_in_zulip_realm from zerver.models import ( MultiuseInvite, PreregistrationUser, Realm, UserMessage, UserProfile, get_org_type_display_name, get_realm, ) from zilencer.lib.remote_counts import MissingDataError if TYPE_CHECKING: from django.test.client import _MonkeyPatchedWSGIResponse as TestHttpResponse import uuid from zilencer.models import RemoteZulipServer class TestRemoteServerSupportEndpoint(ZulipTestCase): @override def setUp(self) -> None: super().setUp() # Set up some initial example data. for i in range(20): hostname = f"zulip-{i}.example.com" RemoteZulipServer.objects.create( hostname=hostname, contact_email=f"admin@{hostname}", plan_type=1, uuid=uuid.uuid4() ) def test_search(self) -> None: self.login("cordelia") result = self.client_get("/activity/remote/support") self.assertEqual(result.status_code, 302) self.assertEqual(result["Location"], "/login/") # Iago is the user with the appropriate permissions to access this page. self.login("iago") assert self.example_user("iago").is_staff result = self.client_get("/activity/remote/support") self.assert_in_success_response( [ 'input type="text" name="q" class="input-xxlarge search-query" placeholder="hostname or contact email"' ], result, ) with mock.patch("analytics.views.support.compute_max_monthly_messages", return_value=1000): result = self.client_get("/activity/remote/support", {"q": "zulip-1.example.com"}) self.assert_in_success_response(["

zulip-1.example.com

"], result) self.assert_in_success_response(["Max monthly messages: 1000"], result) self.assert_not_in_success_response(["

zulip-2.example.com

"], result) with mock.patch( "analytics.views.support.compute_max_monthly_messages", side_effect=MissingDataError ): result = self.client_get("/activity/remote/support", {"q": "zulip-1.example.com"}) self.assert_in_success_response(["

zulip-1.example.com

"], result) self.assert_in_success_response( ["Max monthly messages: Recent data missing"], result ) self.assert_not_in_success_response(["

zulip-2.example.com

"], result) result = self.client_get("/activity/remote/support", {"q": "example.com"}) for i in range(20): self.assert_in_success_response([f"

zulip-{i}.example.com

"], result) result = self.client_get("/activity/remote/support", {"q": "admin@zulip-2.example.com"}) self.assert_in_success_response(["

zulip-2.example.com

"], result) self.assert_in_success_response(["Contact email: admin@zulip-2.example.com"], result) self.assert_not_in_success_response(["

zulip-1.example.com

"], result) class TestSupportEndpoint(ZulipTestCase): def test_search(self) -> None: reset_email_visibility_to_everyone_in_zulip_realm() lear_user = self.lear_user("king") lear_user.is_staff = True lear_user.save(update_fields=["is_staff"]) lear_realm = get_realm("lear") def assert_user_details_in_html_response( html_response: "TestHttpResponse", full_name: str, email: str, role: str ) -> None: self.assert_in_success_response( [ 'user\n', f"

{full_name}

", f"Email: {email}", "Is active: True
", f"Role: {role}
", ], html_response, ) def create_invitation( stream: str, invitee_email: str, realm: Optional[Realm] = None ) -> None: invite_expires_in_minutes = 10 * 24 * 60 self.client_post( "/json/invites", { "invitee_emails": [invitee_email], "stream_ids": orjson.dumps([self.get_stream_id(stream, realm)]).decode(), "invite_expires_in_minutes": invite_expires_in_minutes, "invite_as": PreregistrationUser.INVITE_AS["MEMBER"], }, subdomain=realm.string_id if realm is not None else "zulip", ) def check_hamlet_user_query_result(result: "TestHttpResponse") -> None: assert_user_details_in_html_response( result, "King Hamlet", self.example_email("hamlet"), "Member" ) self.assert_in_success_response( [ f"Admins: {self.example_email('iago')}\n", f"Owners: {self.example_email('desdemona')}\n", 'class="copy-button" data-copytext="{}">'.format(self.example_email("iago")), 'class="copy-button" data-copytext="{}">'.format( self.example_email("desdemona") ), ], result, ) def check_lear_user_query_result(result: "TestHttpResponse") -> None: assert_user_details_in_html_response( result, lear_user.full_name, lear_user.email, "Member" ) def check_othello_user_query_result(result: "TestHttpResponse") -> None: assert_user_details_in_html_response( result, "Othello, the Moor of Venice", self.example_email("othello"), "Member" ) def check_polonius_user_query_result(result: "TestHttpResponse") -> None: assert_user_details_in_html_response( result, "Polonius", self.example_email("polonius"), "Guest" ) def check_zulip_realm_query_result(result: "TestHttpResponse") -> None: zulip_realm = get_realm("zulip") first_human_user = zulip_realm.get_first_human_user() assert first_human_user is not None self.assert_in_success_response( [ f"First human user: {first_human_user.delivery_email}\n", f'", '', '', 'input type="number" name="discount" value="None"', '', '', f'', '', 'input type="number" name="discount" value="None"', '', '', 'scrub-realm-button">', 'data-string-id="lear"', "Name: Zulip Cloud Standard", "Status: Active", "Billing schedule: Annual", "Licenses: 2/10 (Manual)", "Price per license: $80.0", "Next invoice date: 02 January 2017", '