mirror of
https://github.com/zulip/zulip.git
synced 2025-11-03 05:23:35 +00:00
corporate: Move support and activity views to /corporate.
View functions in `analytics/views/support.py` are moved to `corporate/views/support.py`. Shared activity functions in `analytics/views/activity_common.py` are moved to `corporate/lib/activity.py`, which was also renamed from `corporate/lib/analytics.py`.
This commit is contained in:
committed by
Tim Abbott
parent
afba77300a
commit
df2f4b6469
367
corporate/tests/test_activity_views.py
Normal file
367
corporate/tests/test_activity_views.py
Normal file
@@ -0,0 +1,367 @@
|
||||
import uuid
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Optional
|
||||
from unittest import mock
|
||||
|
||||
from django.utils.timezone import now as timezone_now
|
||||
|
||||
from corporate.lib.activity import get_remote_server_audit_logs
|
||||
from corporate.lib.stripe import add_months
|
||||
from corporate.models import Customer, CustomerPlan, LicenseLedger
|
||||
from zerver.lib.test_classes import ZulipTestCase
|
||||
from zerver.models import Client, UserActivity, UserProfile
|
||||
from zilencer.models import (
|
||||
RemoteRealm,
|
||||
RemoteRealmAuditLog,
|
||||
RemoteZulipServer,
|
||||
RemoteZulipServerAuditLog,
|
||||
get_remote_customer_user_count,
|
||||
get_remote_server_guest_and_non_guest_count,
|
||||
)
|
||||
|
||||
event_time = timezone_now() - timedelta(days=3)
|
||||
data_list = [
|
||||
{
|
||||
"server_id": 1,
|
||||
"realm_id": 1,
|
||||
"event_type": RemoteRealmAuditLog.USER_CREATED,
|
||||
"event_time": event_time,
|
||||
"extra_data": {
|
||||
RemoteRealmAuditLog.ROLE_COUNT: {
|
||||
RemoteRealmAuditLog.ROLE_COUNT_HUMANS: {
|
||||
UserProfile.ROLE_REALM_ADMINISTRATOR: 10,
|
||||
UserProfile.ROLE_REALM_OWNER: 10,
|
||||
UserProfile.ROLE_MODERATOR: 10,
|
||||
UserProfile.ROLE_MEMBER: 10,
|
||||
UserProfile.ROLE_GUEST: 10,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"server_id": 1,
|
||||
"realm_id": 1,
|
||||
"event_type": RemoteRealmAuditLog.USER_ROLE_CHANGED,
|
||||
"event_time": event_time,
|
||||
"extra_data": {
|
||||
RemoteRealmAuditLog.ROLE_COUNT: {
|
||||
RemoteRealmAuditLog.ROLE_COUNT_HUMANS: {
|
||||
UserProfile.ROLE_REALM_ADMINISTRATOR: 20,
|
||||
UserProfile.ROLE_REALM_OWNER: 0,
|
||||
UserProfile.ROLE_MODERATOR: 0,
|
||||
UserProfile.ROLE_MEMBER: 20,
|
||||
UserProfile.ROLE_GUEST: 10,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"server_id": 1,
|
||||
"realm_id": 2,
|
||||
"event_type": RemoteRealmAuditLog.USER_CREATED,
|
||||
"event_time": event_time,
|
||||
"extra_data": {
|
||||
RemoteRealmAuditLog.ROLE_COUNT: {
|
||||
RemoteRealmAuditLog.ROLE_COUNT_HUMANS: {
|
||||
UserProfile.ROLE_REALM_ADMINISTRATOR: 10,
|
||||
UserProfile.ROLE_REALM_OWNER: 10,
|
||||
UserProfile.ROLE_MODERATOR: 0,
|
||||
UserProfile.ROLE_MEMBER: 10,
|
||||
UserProfile.ROLE_GUEST: 5,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"server_id": 1,
|
||||
"realm_id": 2,
|
||||
"event_type": RemoteRealmAuditLog.USER_CREATED,
|
||||
"event_time": event_time,
|
||||
"extra_data": {},
|
||||
},
|
||||
{
|
||||
"server_id": 1,
|
||||
"realm_id": 3,
|
||||
"event_type": RemoteRealmAuditLog.USER_CREATED,
|
||||
"event_time": event_time,
|
||||
"extra_data": {
|
||||
RemoteRealmAuditLog.ROLE_COUNT: {
|
||||
RemoteRealmAuditLog.ROLE_COUNT_HUMANS: {
|
||||
UserProfile.ROLE_REALM_ADMINISTRATOR: 1,
|
||||
UserProfile.ROLE_REALM_OWNER: 1,
|
||||
UserProfile.ROLE_MODERATOR: 1,
|
||||
UserProfile.ROLE_MEMBER: 1,
|
||||
UserProfile.ROLE_GUEST: 1,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"server_id": 1,
|
||||
"realm_id": 3,
|
||||
"event_type": RemoteRealmAuditLog.USER_DEACTIVATED,
|
||||
"event_time": event_time + timedelta(seconds=1),
|
||||
"extra_data": {
|
||||
RemoteRealmAuditLog.ROLE_COUNT: {
|
||||
RemoteRealmAuditLog.ROLE_COUNT_HUMANS: {
|
||||
UserProfile.ROLE_REALM_ADMINISTRATOR: 1,
|
||||
UserProfile.ROLE_REALM_OWNER: 1,
|
||||
UserProfile.ROLE_MODERATOR: 1,
|
||||
UserProfile.ROLE_MEMBER: 0,
|
||||
UserProfile.ROLE_GUEST: 1,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class ActivityTest(ZulipTestCase):
|
||||
@mock.patch("stripe.Customer.list", return_value=[])
|
||||
def test_activity(self, unused_mock: mock.Mock) -> None:
|
||||
self.login("hamlet")
|
||||
client, _ = Client.objects.get_or_create(name="website")
|
||||
query = "/json/messages/flags"
|
||||
last_visit = timezone_now()
|
||||
count = 150
|
||||
for activity_user_profile in UserProfile.objects.all():
|
||||
UserActivity.objects.get_or_create(
|
||||
user_profile=activity_user_profile,
|
||||
client=client,
|
||||
query=query,
|
||||
count=count,
|
||||
last_visit=last_visit,
|
||||
)
|
||||
|
||||
# Fails when not staff
|
||||
result = self.client_get("/activity")
|
||||
self.assertEqual(result.status_code, 302)
|
||||
|
||||
user_profile = self.example_user("hamlet")
|
||||
user_profile.is_staff = True
|
||||
user_profile.save(update_fields=["is_staff"])
|
||||
|
||||
with self.assert_database_query_count(11):
|
||||
result = self.client_get("/activity")
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
# Add data for remote activity page
|
||||
remote_realm = RemoteRealm.objects.get(name="Lear & Co.")
|
||||
customer = Customer.objects.create(remote_realm=remote_realm)
|
||||
plan = CustomerPlan.objects.create(
|
||||
customer=customer,
|
||||
billing_cycle_anchor=timezone_now(),
|
||||
billing_schedule=CustomerPlan.BILLING_SCHEDULE_ANNUAL,
|
||||
tier=CustomerPlan.TIER_SELF_HOSTED_BUSINESS,
|
||||
price_per_license=8000,
|
||||
next_invoice_date=add_months(timezone_now(), 12),
|
||||
)
|
||||
LicenseLedger.objects.create(
|
||||
licenses=10,
|
||||
licenses_at_next_renewal=10,
|
||||
event_time=timezone_now(),
|
||||
is_renewal=True,
|
||||
plan=plan,
|
||||
)
|
||||
server = RemoteZulipServer.objects.create(
|
||||
uuid=str(uuid.uuid4()),
|
||||
api_key="magic_secret_api_key",
|
||||
hostname="demo.example.com",
|
||||
contact_email="email@example.com",
|
||||
)
|
||||
extra_data = {
|
||||
RemoteRealmAuditLog.ROLE_COUNT: {
|
||||
RemoteRealmAuditLog.ROLE_COUNT_HUMANS: {
|
||||
UserProfile.ROLE_REALM_ADMINISTRATOR: 1,
|
||||
UserProfile.ROLE_REALM_OWNER: 1,
|
||||
UserProfile.ROLE_MODERATOR: 1,
|
||||
UserProfile.ROLE_MEMBER: 1,
|
||||
UserProfile.ROLE_GUEST: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
RemoteRealmAuditLog.objects.create(
|
||||
server=server,
|
||||
realm_id=10,
|
||||
event_type=RemoteRealmAuditLog.USER_CREATED,
|
||||
event_time=timezone_now() - timedelta(days=1),
|
||||
extra_data=extra_data,
|
||||
)
|
||||
with self.assert_database_query_count(9):
|
||||
result = self.client_get("/activity/remote")
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
with self.assert_database_query_count(4):
|
||||
result = self.client_get("/activity/integrations")
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
with self.assert_database_query_count(6):
|
||||
result = self.client_get("/realm_activity/zulip/")
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
iago = self.example_user("iago")
|
||||
with self.assert_database_query_count(5):
|
||||
result = self.client_get(f"/user_activity/{iago.id}/")
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
def test_get_remote_server_guest_and_non_guest_count(self) -> None:
|
||||
RemoteRealmAuditLog.objects.bulk_create([RemoteRealmAuditLog(**data) for data in data_list])
|
||||
server_id = 1
|
||||
|
||||
# Used in billing code
|
||||
remote_server_counts = get_remote_server_guest_and_non_guest_count(
|
||||
server_id=server_id, event_time=timezone_now()
|
||||
)
|
||||
self.assertEqual(remote_server_counts.non_guest_user_count, 73)
|
||||
self.assertEqual(remote_server_counts.guest_user_count, 16)
|
||||
|
||||
# Used in remote activity view code
|
||||
server_logs = get_remote_server_audit_logs()
|
||||
remote_activity_counts = get_remote_customer_user_count(server_logs[server_id])
|
||||
self.assertEqual(remote_activity_counts.non_guest_user_count, 73)
|
||||
self.assertEqual(remote_activity_counts.guest_user_count, 16)
|
||||
|
||||
def test_remote_activity_with_robust_data(self) -> None:
|
||||
def add_plan(customer: Customer, tier: int, fixed_price: bool = False) -> None:
|
||||
if fixed_price:
|
||||
plan = CustomerPlan.objects.create(
|
||||
customer=customer,
|
||||
billing_cycle_anchor=timezone_now(),
|
||||
billing_schedule=CustomerPlan.BILLING_SCHEDULE_ANNUAL,
|
||||
tier=tier,
|
||||
fixed_price=10000,
|
||||
next_invoice_date=add_months(timezone_now(), 12),
|
||||
)
|
||||
else:
|
||||
if tier in (
|
||||
CustomerPlan.TIER_SELF_HOSTED_BASE,
|
||||
CustomerPlan.TIER_SELF_HOSTED_LEGACY,
|
||||
CustomerPlan.TIER_SELF_HOSTED_COMMUNITY,
|
||||
):
|
||||
price_per_license = 0
|
||||
else:
|
||||
price_per_license = 1000
|
||||
plan = CustomerPlan.objects.create(
|
||||
customer=customer,
|
||||
billing_cycle_anchor=timezone_now(),
|
||||
billing_schedule=CustomerPlan.BILLING_SCHEDULE_ANNUAL,
|
||||
tier=tier,
|
||||
price_per_license=price_per_license,
|
||||
next_invoice_date=add_months(timezone_now(), 12),
|
||||
)
|
||||
LicenseLedger.objects.create(
|
||||
licenses=10,
|
||||
licenses_at_next_renewal=10,
|
||||
event_time=timezone_now(),
|
||||
is_renewal=True,
|
||||
plan=plan,
|
||||
)
|
||||
|
||||
def add_audit_log_data(
|
||||
server: RemoteZulipServer, remote_realm: Optional[RemoteRealm], realm_id: Optional[int]
|
||||
) -> None:
|
||||
extra_data = {
|
||||
RemoteRealmAuditLog.ROLE_COUNT: {
|
||||
RemoteRealmAuditLog.ROLE_COUNT_HUMANS: {
|
||||
UserProfile.ROLE_REALM_ADMINISTRATOR: 1,
|
||||
UserProfile.ROLE_REALM_OWNER: 1,
|
||||
UserProfile.ROLE_MODERATOR: 0,
|
||||
UserProfile.ROLE_MEMBER: 0,
|
||||
UserProfile.ROLE_GUEST: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
if remote_realm is not None:
|
||||
RemoteRealmAuditLog.objects.create(
|
||||
server=server,
|
||||
remote_realm=remote_realm,
|
||||
event_type=RemoteRealmAuditLog.USER_CREATED,
|
||||
event_time=timezone_now() - timedelta(days=1),
|
||||
extra_data=extra_data,
|
||||
)
|
||||
else:
|
||||
RemoteRealmAuditLog.objects.create(
|
||||
server=server,
|
||||
realm_id=realm_id,
|
||||
event_type=RemoteRealmAuditLog.USER_CREATED,
|
||||
event_time=timezone_now() - timedelta(days=1),
|
||||
extra_data=extra_data,
|
||||
)
|
||||
|
||||
for i in range(6):
|
||||
hostname = f"zulip-{i}.example.com"
|
||||
remote_server = RemoteZulipServer.objects.create(
|
||||
hostname=hostname, contact_email=f"admin@{hostname}", uuid=uuid.uuid4()
|
||||
)
|
||||
RemoteZulipServerAuditLog.objects.create(
|
||||
event_type=RemoteZulipServerAuditLog.REMOTE_SERVER_CREATED,
|
||||
server=remote_server,
|
||||
event_time=remote_server.last_updated,
|
||||
)
|
||||
# We want at least one RemoteZulipServer that has no RemoteRealm
|
||||
# as an example of a pre-8.0 release registered remote server.
|
||||
if i > 2:
|
||||
realm_name = f"realm-name-{i}"
|
||||
realm_host = f"realm-host-{i}"
|
||||
realm_uuid = uuid.uuid4()
|
||||
RemoteRealm.objects.create(
|
||||
server=remote_server,
|
||||
uuid=realm_uuid,
|
||||
host=realm_host,
|
||||
name=realm_name,
|
||||
realm_date_created=datetime(2023, 12, 1, tzinfo=timezone.utc),
|
||||
)
|
||||
|
||||
# Remote server on legacy plan
|
||||
server = RemoteZulipServer.objects.get(hostname="zulip-1.example.com")
|
||||
customer = Customer.objects.create(remote_server=server)
|
||||
add_plan(customer, tier=CustomerPlan.TIER_SELF_HOSTED_LEGACY)
|
||||
add_audit_log_data(server, remote_realm=None, realm_id=2)
|
||||
|
||||
# Remote server paid plan - multiple realms
|
||||
server = RemoteZulipServer.objects.get(hostname="zulip-2.example.com")
|
||||
customer = Customer.objects.create(remote_server=server)
|
||||
add_plan(customer, tier=CustomerPlan.TIER_SELF_HOSTED_BASIC)
|
||||
add_audit_log_data(server, remote_realm=None, realm_id=3)
|
||||
add_audit_log_data(server, remote_realm=None, realm_id=4)
|
||||
add_audit_log_data(server, remote_realm=None, realm_id=5)
|
||||
|
||||
# Single remote realm on remote server - community plan
|
||||
realm = RemoteRealm.objects.get(name="realm-name-3")
|
||||
customer = Customer.objects.create(remote_realm=realm)
|
||||
add_plan(customer, tier=CustomerPlan.TIER_SELF_HOSTED_COMMUNITY)
|
||||
add_audit_log_data(realm.server, remote_realm=realm, realm_id=None)
|
||||
|
||||
# Single remote realm on remote server - paid plan
|
||||
realm = RemoteRealm.objects.get(name="realm-name-4")
|
||||
customer = Customer.objects.create(remote_realm=realm)
|
||||
add_plan(customer, tier=CustomerPlan.TIER_SELF_HOSTED_BUSINESS)
|
||||
add_audit_log_data(realm.server, remote_realm=realm, realm_id=None)
|
||||
|
||||
# Multiple remote realms on remote server - on different paid plans
|
||||
realm = RemoteRealm.objects.get(name="realm-name-5")
|
||||
customer = Customer.objects.create(remote_realm=realm)
|
||||
add_plan(customer, tier=CustomerPlan.TIER_SELF_HOSTED_BASIC)
|
||||
add_audit_log_data(realm.server, remote_realm=realm, realm_id=None)
|
||||
|
||||
remote_server = realm.server
|
||||
realm_name = "realm-name-6"
|
||||
realm_host = "realm-host-6"
|
||||
realm_uuid = uuid.uuid4()
|
||||
RemoteRealm.objects.create(
|
||||
server=remote_server,
|
||||
uuid=realm_uuid,
|
||||
host=realm_host,
|
||||
name=realm_name,
|
||||
realm_date_created=datetime(2023, 12, 1, tzinfo=timezone.utc),
|
||||
)
|
||||
|
||||
realm = RemoteRealm.objects.get(name="realm-name-6")
|
||||
customer = Customer.objects.create(remote_realm=realm)
|
||||
add_plan(customer, tier=CustomerPlan.TIER_SELF_HOSTED_BASIC, fixed_price=True)
|
||||
add_audit_log_data(realm.server, remote_realm=realm, realm_id=None)
|
||||
|
||||
self.login("iago")
|
||||
with self.assert_database_query_count(11):
|
||||
result = self.client_get("/activity/remote")
|
||||
self.assertEqual(result.status_code, 200)
|
||||
Reference in New Issue
Block a user