mirror of
https://github.com/zulip/zulip.git
synced 2025-11-13 10:26:28 +00:00
populate_billing_realms: Add method to populate remote realms.
We also avoid deleting all RemoteZulipServer at start so that we don't delete the registered server for remote realms.
This commit is contained in:
@@ -5,12 +5,14 @@ from datetime import datetime, timezone
|
|||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
import stripe
|
import stripe
|
||||||
|
from django.conf import settings
|
||||||
from django.core.management.base import BaseCommand, CommandParser
|
from django.core.management.base import BaseCommand, CommandParser
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
|
||||||
from corporate.lib.stripe import (
|
from corporate.lib.stripe import (
|
||||||
RealmBillingSession,
|
RealmBillingSession,
|
||||||
|
RemoteRealmBillingSession,
|
||||||
RemoteServerBillingSession,
|
RemoteServerBillingSession,
|
||||||
UpgradeRequest,
|
UpgradeRequest,
|
||||||
add_months,
|
add_months,
|
||||||
@@ -22,9 +24,11 @@ from zerver.actions.create_realm import do_create_realm
|
|||||||
from zerver.actions.create_user import do_create_user
|
from zerver.actions.create_user import do_create_user
|
||||||
from zerver.actions.streams import bulk_add_subscriptions
|
from zerver.actions.streams import bulk_add_subscriptions
|
||||||
from zerver.apps import flush_cache
|
from zerver.apps import flush_cache
|
||||||
|
from zerver.lib.remote_server import get_realms_info_for_push_bouncer
|
||||||
from zerver.lib.streams import create_stream_if_needed
|
from zerver.lib.streams import create_stream_if_needed
|
||||||
from zerver.models import Realm, UserProfile, get_realm
|
from zerver.models import Realm, UserProfile, get_realm
|
||||||
from zilencer.models import RemoteZulipServer
|
from zilencer.models import RemoteRealm, RemoteZulipServer
|
||||||
|
from zilencer.views import update_remote_realm_data_for_server
|
||||||
from zproject.config import get_secret
|
from zproject.config import get_secret
|
||||||
|
|
||||||
current_time = timezone_now().strftime(TIMESTAMP_FORMAT)
|
current_time = timezone_now().strftime(TIMESTAMP_FORMAT)
|
||||||
@@ -60,6 +64,12 @@ class Command(BaseCommand):
|
|||||||
help="Whether to only run for remote servers",
|
help="Whether to only run for remote servers",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--only-remote-realm",
|
||||||
|
action="store_true",
|
||||||
|
help="Whether to only run for remote realms",
|
||||||
|
)
|
||||||
|
|
||||||
@override
|
@override
|
||||||
def handle(self, *args: Any, **options: Any) -> None:
|
def handle(self, *args: Any, **options: Any) -> None:
|
||||||
# Create a realm for each plan type
|
# Create a realm for each plan type
|
||||||
@@ -129,7 +139,8 @@ class Command(BaseCommand):
|
|||||||
unique_id="sponsored",
|
unique_id="sponsored",
|
||||||
is_sponsored=True,
|
is_sponsored=True,
|
||||||
billing_schedule=CustomerPlan.BILLING_SCHEDULE_MONTHLY,
|
billing_schedule=CustomerPlan.BILLING_SCHEDULE_MONTHLY,
|
||||||
tier=CustomerPlan.TIER_CLOUD_STANDARD,
|
# Customer plan might not exist for sponsored realms.
|
||||||
|
tier=CustomerPlan.TIER_CLOUD_COMMUNITY,
|
||||||
),
|
),
|
||||||
CustomerProfile(
|
CustomerProfile(
|
||||||
unique_id="free-trial",
|
unique_id="free-trial",
|
||||||
@@ -173,22 +184,54 @@ class Command(BaseCommand):
|
|||||||
),
|
),
|
||||||
CustomerProfile(
|
CustomerProfile(
|
||||||
unique_id="server-sponsored",
|
unique_id="server-sponsored",
|
||||||
tier=CustomerPlan.TIER_SELF_HOSTED_BUSINESS,
|
tier=CustomerPlan.TIER_SELF_HOSTED_COMMUNITY,
|
||||||
is_sponsored=True,
|
is_sponsored=True,
|
||||||
is_remote_server=True,
|
is_remote_server=True,
|
||||||
),
|
),
|
||||||
|
CustomerProfile(
|
||||||
|
unique_id="free-tier-remote-realm",
|
||||||
|
is_remote_realm=True,
|
||||||
|
),
|
||||||
|
CustomerProfile(
|
||||||
|
unique_id="business-remote-realm",
|
||||||
|
tier=CustomerPlan.TIER_SELF_HOSTED_BUSINESS,
|
||||||
|
is_remote_realm=True,
|
||||||
|
),
|
||||||
|
CustomerProfile(
|
||||||
|
unique_id="business-remote-free-trial",
|
||||||
|
tier=CustomerPlan.TIER_SELF_HOSTED_BUSINESS,
|
||||||
|
status=CustomerPlan.FREE_TRIAL,
|
||||||
|
is_remote_realm=True,
|
||||||
|
),
|
||||||
|
CustomerProfile(
|
||||||
|
unique_id="business-remote-sponsorship-pending",
|
||||||
|
tier=CustomerPlan.TIER_SELF_HOSTED_BUSINESS,
|
||||||
|
sponsorship_pending=True,
|
||||||
|
is_remote_realm=True,
|
||||||
|
),
|
||||||
|
CustomerProfile(
|
||||||
|
unique_id="remote-sponsorship-pending",
|
||||||
|
sponsorship_pending=True,
|
||||||
|
is_remote_realm=True,
|
||||||
|
),
|
||||||
|
CustomerProfile(
|
||||||
|
unique_id="remote-realm-sponsored",
|
||||||
|
tier=CustomerPlan.TIER_SELF_HOSTED_COMMUNITY,
|
||||||
|
is_sponsored=True,
|
||||||
|
is_remote_realm=True,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Delete all existing remote servers
|
|
||||||
RemoteZulipServer.objects.all().delete()
|
|
||||||
flush_cache(None)
|
|
||||||
|
|
||||||
servers = []
|
servers = []
|
||||||
|
remote_realms = []
|
||||||
for customer_profile in customer_profiles:
|
for customer_profile in customer_profiles:
|
||||||
if customer_profile.is_remote_server:
|
if customer_profile.is_remote_server and not options.get("only_remote_realm"):
|
||||||
server_conf = populate_remote_server(customer_profile)
|
server_conf = populate_remote_server(customer_profile)
|
||||||
servers.append(server_conf)
|
servers.append(server_conf)
|
||||||
elif not options.get("only_remote_server"):
|
elif customer_profile.is_remote_realm and not options.get("only_remote_server"):
|
||||||
|
remote_realm_conf = populate_remote_realms(customer_profile)
|
||||||
|
remote_realms.append(remote_realm_conf)
|
||||||
|
elif not options.get("only_remote_server") and not options.get("only_remote_realm"):
|
||||||
populate_realm(customer_profile)
|
populate_realm(customer_profile)
|
||||||
|
|
||||||
print("-" * 40)
|
print("-" * 40)
|
||||||
@@ -197,6 +240,11 @@ class Command(BaseCommand):
|
|||||||
print(f"{key}: {value}")
|
print(f"{key}: {value}")
|
||||||
print("-" * 40)
|
print("-" * 40)
|
||||||
|
|
||||||
|
for remote_realm_conf in remote_realms:
|
||||||
|
for key, value in remote_realm_conf.items():
|
||||||
|
print(f"{key}: {value}")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
|
||||||
def add_card_to_customer(customer: Customer) -> None:
|
def add_card_to_customer(customer: Customer) -> None:
|
||||||
assert customer.stripe_customer_id is not None
|
assert customer.stripe_customer_id is not None
|
||||||
@@ -247,11 +295,14 @@ def create_plan_for_customer(customer: Customer, customer_profile: CustomerProfi
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def populate_realm(customer_profile: CustomerProfile) -> Optional[Realm]:
|
||||||
unique_id = customer_profile.unique_id
|
unique_id = customer_profile.unique_id
|
||||||
if customer_profile.tier is None:
|
if customer_profile.is_remote_realm:
|
||||||
|
plan_type = Realm.PLAN_TYPE_SELF_HOSTED
|
||||||
|
elif customer_profile.tier is None:
|
||||||
plan_type = Realm.PLAN_TYPE_LIMITED
|
plan_type = Realm.PLAN_TYPE_LIMITED
|
||||||
elif (
|
elif (
|
||||||
customer_profile.tier == CustomerPlan.TIER_CLOUD_STANDARD and customer_profile.is_sponsored
|
customer_profile.tier == CustomerPlan.TIER_CLOUD_COMMUNITY and customer_profile.is_sponsored
|
||||||
):
|
):
|
||||||
plan_type = Realm.PLAN_TYPE_STANDARD_FREE
|
plan_type = Realm.PLAN_TYPE_STANDARD_FREE
|
||||||
elif customer_profile.tier == CustomerPlan.TIER_CLOUD_STANDARD:
|
elif customer_profile.tier == CustomerPlan.TIER_CLOUD_STANDARD:
|
||||||
@@ -290,6 +341,7 @@ def create_plan_for_customer(customer: Customer, customer_profile: CustomerProfi
|
|||||||
full_name,
|
full_name,
|
||||||
role=UserProfile.ROLE_REALM_OWNER,
|
role=UserProfile.ROLE_REALM_OWNER,
|
||||||
acting_user=None,
|
acting_user=None,
|
||||||
|
tos_version=settings.TERMS_OF_SERVICE_VERSION,
|
||||||
)
|
)
|
||||||
|
|
||||||
stream, _ = create_stream_if_needed(
|
stream, _ = create_stream_if_needed(
|
||||||
@@ -299,15 +351,19 @@ def create_plan_for_customer(customer: Customer, customer_profile: CustomerProfi
|
|||||||
|
|
||||||
bulk_add_subscriptions(realm, [stream], [user], acting_user=None)
|
bulk_add_subscriptions(realm, [stream], [user], acting_user=None)
|
||||||
|
|
||||||
|
if customer_profile.is_remote_realm:
|
||||||
|
# Remote realm billing data on their local server is irrelevant.
|
||||||
|
return realm
|
||||||
|
|
||||||
if customer_profile.sponsorship_pending:
|
if customer_profile.sponsorship_pending:
|
||||||
customer = Customer.objects.create(
|
customer = Customer.objects.create(
|
||||||
realm=realm,
|
realm=realm,
|
||||||
sponsorship_pending=customer_profile.sponsorship_pending,
|
sponsorship_pending=customer_profile.sponsorship_pending,
|
||||||
)
|
)
|
||||||
return
|
return realm
|
||||||
|
|
||||||
if customer_profile.tier is None:
|
if customer_profile.tier is None:
|
||||||
return
|
return realm
|
||||||
|
|
||||||
billing_session = RealmBillingSession(user)
|
billing_session = RealmBillingSession(user)
|
||||||
customer = billing_session.update_or_create_stripe_customer()
|
customer = billing_session.update_or_create_stripe_customer()
|
||||||
@@ -335,6 +391,11 @@ def populate_remote_server(customer_profile: CustomerProfile) -> Dict[str, str]:
|
|||||||
|
|
||||||
server_uuid = str(uuid.uuid4())
|
server_uuid = str(uuid.uuid4())
|
||||||
api_key = server_uuid
|
api_key = server_uuid
|
||||||
|
hostname = f"{unique_id}.example.com"
|
||||||
|
|
||||||
|
# Delete existing remote server.
|
||||||
|
RemoteZulipServer.objects.filter(hostname=hostname).delete()
|
||||||
|
flush_cache(None)
|
||||||
|
|
||||||
remote_server = RemoteZulipServer.objects.create(
|
remote_server = RemoteZulipServer.objects.create(
|
||||||
uuid=server_uuid,
|
uuid=server_uuid,
|
||||||
@@ -390,3 +451,40 @@ def populate_remote_server(customer_profile: CustomerProfile) -> Dict[str, str]:
|
|||||||
"server_uuid": server_uuid,
|
"server_uuid": server_uuid,
|
||||||
"api_key": api_key,
|
"api_key": api_key,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def populate_remote_realms(customer_profile: CustomerProfile) -> Dict[str, str]:
|
||||||
|
local_realm = populate_realm(customer_profile)
|
||||||
|
assert local_realm is not None
|
||||||
|
|
||||||
|
remote_server_uuid = settings.ZULIP_ORG_ID
|
||||||
|
assert remote_server_uuid is not None
|
||||||
|
remote_server = RemoteZulipServer.objects.filter(
|
||||||
|
uuid=remote_server_uuid,
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if remote_server is None:
|
||||||
|
raise AssertionError("Remote server not found! Please run manage.py register_server")
|
||||||
|
|
||||||
|
update_remote_realm_data_for_server(
|
||||||
|
remote_server, get_realms_info_for_push_bouncer(local_realm.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
remote_realm = RemoteRealm.objects.get(uuid=local_realm.uuid)
|
||||||
|
billing_session = RemoteRealmBillingSession(remote_realm)
|
||||||
|
customer = billing_session.update_or_create_stripe_customer()
|
||||||
|
assert customer.stripe_customer_id is not None
|
||||||
|
add_card_to_customer(customer)
|
||||||
|
if customer_profile.tier is not None:
|
||||||
|
billing_session.do_change_plan_type(
|
||||||
|
tier=customer_profile.tier, is_sponsored=customer_profile.is_sponsored
|
||||||
|
)
|
||||||
|
create_plan_for_customer(customer, customer_profile)
|
||||||
|
|
||||||
|
if customer_profile.sponsorship_pending:
|
||||||
|
billing_session.update_customer_sponsorship_status(True)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"unique_id": customer_profile.unique_id,
|
||||||
|
"login_url": local_realm.uri + "/self-hosted-billing/",
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user