mirror of
https://github.com/zulip/zulip.git
synced 2025-11-01 20:44:04 +00:00
models: Add plan_type to Realm.
This commit is contained in:
@@ -3018,6 +3018,15 @@ def do_change_icon_source(realm: Realm, icon_source: str, log: bool=True) -> Non
|
|||||||
icon_url=realm_icon_url(realm))),
|
icon_url=realm_icon_url(realm))),
|
||||||
active_user_ids(realm.id))
|
active_user_ids(realm.id))
|
||||||
|
|
||||||
|
def do_change_plan_type(user: UserProfile, plan_type: int) -> None:
|
||||||
|
realm = user.realm
|
||||||
|
old_value = realm.plan_type
|
||||||
|
realm.plan_type = plan_type
|
||||||
|
realm.save(update_fields=['plan_type'])
|
||||||
|
RealmAuditLog.objects.create(event_type=RealmAuditLog.REALM_PLAN_TYPE_CHANGED,
|
||||||
|
realm=realm, acting_user=user, event_time=timezone_now(),
|
||||||
|
extra_data={'old_value': old_value, 'new_value': plan_type})
|
||||||
|
|
||||||
def do_change_default_sending_stream(user_profile: UserProfile, stream: Optional[Stream],
|
def do_change_default_sending_stream(user_profile: UserProfile, stream: Optional[Stream],
|
||||||
log: bool=True) -> None:
|
log: bool=True) -> None:
|
||||||
user_profile.default_sending_stream = stream
|
user_profile.default_sending_stream = stream
|
||||||
@@ -3194,6 +3203,8 @@ def do_create_realm(string_id: str, name: str,
|
|||||||
kwargs = {} # type: Dict[str, Any]
|
kwargs = {} # type: Dict[str, Any]
|
||||||
if emails_restricted_to_domains is not None:
|
if emails_restricted_to_domains is not None:
|
||||||
kwargs['emails_restricted_to_domains'] = emails_restricted_to_domains
|
kwargs['emails_restricted_to_domains'] = emails_restricted_to_domains
|
||||||
|
if settings.BILLING_ENABLED:
|
||||||
|
kwargs['plan_type'] = Realm.LIMITED
|
||||||
realm = Realm(string_id=string_id, name=name, **kwargs)
|
realm = Realm(string_id=string_id, name=name, **kwargs)
|
||||||
realm.save()
|
realm.save()
|
||||||
|
|
||||||
|
|||||||
22
zerver/migrations/0185_realm_plan_type.py
Normal file
22
zerver/migrations/0185_realm_plan_type.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.14 on 2018-08-10 21:36
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import zerver.models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('zerver', '0184_rename_custom_field_types'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='realm',
|
||||||
|
name='plan_type',
|
||||||
|
# Realm.SELF_HOSTED
|
||||||
|
field=models.PositiveSmallIntegerField(default=1),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -223,6 +223,15 @@ class Realm(models.Model):
|
|||||||
COMMUNITY = 2
|
COMMUNITY = 2
|
||||||
org_type = models.PositiveSmallIntegerField(default=CORPORATE) # type: int
|
org_type = models.PositiveSmallIntegerField(default=CORPORATE) # type: int
|
||||||
|
|
||||||
|
# plan_type controls various features around resource/feature
|
||||||
|
# limitations for a Zulip organization on multi-tenant servers
|
||||||
|
# like zulipchat.com.
|
||||||
|
SELF_HOSTED = 1
|
||||||
|
LIMITED = 2
|
||||||
|
PREMIUM = 3
|
||||||
|
PREMIUM_FREE = 4
|
||||||
|
plan_type = models.PositiveSmallIntegerField(default=SELF_HOSTED) # type: int
|
||||||
|
|
||||||
# This value is also being used in static/js/settings_bots.bot_creation_policy_values.
|
# This value is also being used in static/js/settings_bots.bot_creation_policy_values.
|
||||||
# On updating it here, update it there as well.
|
# On updating it here, update it there as well.
|
||||||
BOT_CREATION_EVERYONE = 1
|
BOT_CREATION_EVERYONE = 1
|
||||||
@@ -2189,6 +2198,7 @@ class RealmAuditLog(models.Model):
|
|||||||
|
|
||||||
REALM_DEACTIVATED = 'realm_deactivated'
|
REALM_DEACTIVATED = 'realm_deactivated'
|
||||||
REALM_REACTIVATED = 'realm_reactivated'
|
REALM_REACTIVATED = 'realm_reactivated'
|
||||||
|
REALM_PLAN_TYPE_CHANGED = 'realm_plan_type_changed'
|
||||||
|
|
||||||
SUBSCRIPTION_CREATED = 'subscription_created'
|
SUBSCRIPTION_CREATED = 'subscription_created'
|
||||||
SUBSCRIPTION_ACTIVATED = 'subscription_activated'
|
SUBSCRIPTION_ACTIVATED = 'subscription_activated'
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from zerver.lib.actions import (
|
|||||||
do_set_realm_property,
|
do_set_realm_property,
|
||||||
do_deactivate_realm,
|
do_deactivate_realm,
|
||||||
do_deactivate_stream,
|
do_deactivate_stream,
|
||||||
|
do_create_realm,
|
||||||
)
|
)
|
||||||
|
|
||||||
from zerver.lib.send_email import send_future_email
|
from zerver.lib.send_email import send_future_email
|
||||||
@@ -334,6 +335,12 @@ class RealmTest(ZulipTestCase):
|
|||||||
self.assert_json_success(result)
|
self.assert_json_success(result)
|
||||||
self.assertEqual(get_realm('zulip').video_chat_provider, "Jitsi")
|
self.assertEqual(get_realm('zulip').video_chat_provider, "Jitsi")
|
||||||
|
|
||||||
|
def test_initial_plan_type(self) -> None:
|
||||||
|
with self.settings(BILLING_ENABLED=True):
|
||||||
|
self.assertEqual(Realm.LIMITED, do_create_realm('hosted', 'hosted').plan_type)
|
||||||
|
with self.settings(BILLING_ENABLED=False):
|
||||||
|
self.assertEqual(Realm.SELF_HOSTED, do_create_realm('onpremise', 'onpremise').plan_type)
|
||||||
|
|
||||||
class RealmAPITest(ZulipTestCase):
|
class RealmAPITest(ZulipTestCase):
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from zerver.lib.exceptions import JsonableError
|
|||||||
from zerver.lib.logging_util import log_to_file
|
from zerver.lib.logging_util import log_to_file
|
||||||
from zerver.lib.timestamp import datetime_to_timestamp, timestamp_to_datetime
|
from zerver.lib.timestamp import datetime_to_timestamp, timestamp_to_datetime
|
||||||
from zerver.lib.utils import generate_random_token
|
from zerver.lib.utils import generate_random_token
|
||||||
|
from zerver.lib.actions import do_change_plan_type
|
||||||
from zerver.models import Realm, UserProfile, RealmAuditLog
|
from zerver.models import Realm, UserProfile, RealmAuditLog
|
||||||
from zilencer.models import Customer, Plan, BillingProcessor
|
from zilencer.models import Customer, Plan, BillingProcessor
|
||||||
from zproject.settings import get_secret
|
from zproject.settings import get_secret
|
||||||
@@ -228,6 +229,7 @@ def process_initial_upgrade(user: UserProfile, plan: Plan, seat_count: int, stri
|
|||||||
# TODO: billing address details are passed to us in the request;
|
# TODO: billing address details are passed to us in the request;
|
||||||
# use that to calculate taxes.
|
# use that to calculate taxes.
|
||||||
tax_percent=0)
|
tax_percent=0)
|
||||||
|
do_change_plan_type(user, Realm.PREMIUM)
|
||||||
|
|
||||||
## Process RealmAuditLog
|
## Process RealmAuditLog
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ def mock_customer_with_cancel_at_period_end_subscription(*args: Any, **kwargs: A
|
|||||||
def mock_upcoming_invoice(*args: Any, **kwargs: Any) -> stripe.Invoice:
|
def mock_upcoming_invoice(*args: Any, **kwargs: Any) -> stripe.Invoice:
|
||||||
return stripe.util.convert_to_stripe_object(fixture_data["upcoming_invoice"])
|
return stripe.util.convert_to_stripe_object(fixture_data["upcoming_invoice"])
|
||||||
|
|
||||||
|
# A Kandra is a fictional character that can become anything. Used as a
|
||||||
|
# wildcard when testing for equality.
|
||||||
|
class Kandra(object):
|
||||||
|
def __eq__(self, other: Any) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
class StripeTest(ZulipTestCase):
|
class StripeTest(ZulipTestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
self.token = 'token'
|
self.token = 'token'
|
||||||
@@ -103,6 +109,7 @@ class StripeTest(ZulipTestCase):
|
|||||||
response = self.client_get("/upgrade/")
|
response = self.client_get("/upgrade/")
|
||||||
self.assert_in_success_response(['We can also bill by invoice'], response)
|
self.assert_in_success_response(['We can also bill by invoice'], response)
|
||||||
self.assertFalse(user.realm.has_seat_based_plan)
|
self.assertFalse(user.realm.has_seat_based_plan)
|
||||||
|
self.assertNotEqual(user.realm.plan_type, Realm.PREMIUM)
|
||||||
|
|
||||||
# Click "Make payment" in Stripe Checkout
|
# Click "Make payment" in Stripe Checkout
|
||||||
self.client_post("/upgrade/", {
|
self.client_post("/upgrade/", {
|
||||||
@@ -135,10 +142,12 @@ class StripeTest(ZulipTestCase):
|
|||||||
(RealmAuditLog.STRIPE_CUSTOMER_CREATED, timestamp_to_datetime(self.customer_created)),
|
(RealmAuditLog.STRIPE_CUSTOMER_CREATED, timestamp_to_datetime(self.customer_created)),
|
||||||
(RealmAuditLog.STRIPE_CARD_ADDED, timestamp_to_datetime(self.customer_created)),
|
(RealmAuditLog.STRIPE_CARD_ADDED, timestamp_to_datetime(self.customer_created)),
|
||||||
(RealmAuditLog.STRIPE_PLAN_CHANGED, timestamp_to_datetime(self.subscription_created)),
|
(RealmAuditLog.STRIPE_PLAN_CHANGED, timestamp_to_datetime(self.subscription_created)),
|
||||||
|
(RealmAuditLog.REALM_PLAN_TYPE_CHANGED, Kandra()),
|
||||||
])
|
])
|
||||||
# Check that we correctly updated Realm
|
# Check that we correctly updated Realm
|
||||||
realm = get_realm("zulip")
|
realm = get_realm("zulip")
|
||||||
self.assertTrue(realm.has_seat_based_plan)
|
self.assertTrue(realm.has_seat_based_plan)
|
||||||
|
self.assertEqual(realm.plan_type, Realm.PREMIUM)
|
||||||
# Check that we can no longer access /upgrade
|
# Check that we can no longer access /upgrade
|
||||||
response = self.client_get("/upgrade/")
|
response = self.client_get("/upgrade/")
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
@@ -202,12 +211,13 @@ class StripeTest(ZulipTestCase):
|
|||||||
# correctly handled the requires_billing_update field
|
# correctly handled the requires_billing_update field
|
||||||
audit_log_entries = list(RealmAuditLog.objects.order_by('-id')
|
audit_log_entries = list(RealmAuditLog.objects.order_by('-id')
|
||||||
.values_list('event_type', 'event_time',
|
.values_list('event_type', 'event_time',
|
||||||
'requires_billing_update')[:4])[::-1]
|
'requires_billing_update')[:5])[::-1]
|
||||||
self.assertEqual(audit_log_entries, [
|
self.assertEqual(audit_log_entries, [
|
||||||
(RealmAuditLog.STRIPE_CUSTOMER_CREATED, timestamp_to_datetime(self.customer_created), False),
|
(RealmAuditLog.STRIPE_CUSTOMER_CREATED, timestamp_to_datetime(self.customer_created), False),
|
||||||
(RealmAuditLog.STRIPE_CARD_ADDED, timestamp_to_datetime(self.customer_created), False),
|
(RealmAuditLog.STRIPE_CARD_ADDED, timestamp_to_datetime(self.customer_created), False),
|
||||||
(RealmAuditLog.STRIPE_PLAN_CHANGED, timestamp_to_datetime(self.subscription_created), False),
|
(RealmAuditLog.STRIPE_PLAN_CHANGED, timestamp_to_datetime(self.subscription_created), False),
|
||||||
(RealmAuditLog.STRIPE_PLAN_QUANTITY_RESET, timestamp_to_datetime(self.subscription_created), True),
|
(RealmAuditLog.STRIPE_PLAN_QUANTITY_RESET, timestamp_to_datetime(self.subscription_created), True),
|
||||||
|
(RealmAuditLog.REALM_PLAN_TYPE_CHANGED, Kandra(), False),
|
||||||
])
|
])
|
||||||
self.assertEqual(ujson.loads(RealmAuditLog.objects.filter(
|
self.assertEqual(ujson.loads(RealmAuditLog.objects.filter(
|
||||||
event_type=RealmAuditLog.STRIPE_PLAN_QUANTITY_RESET).values_list('extra_data', flat=True).first()),
|
event_type=RealmAuditLog.STRIPE_PLAN_QUANTITY_RESET).values_list('extra_data', flat=True).first()),
|
||||||
@@ -261,7 +271,8 @@ class StripeTest(ZulipTestCase):
|
|||||||
self.assertEqual(audit_log_entries, [RealmAuditLog.STRIPE_CUSTOMER_CREATED,
|
self.assertEqual(audit_log_entries, [RealmAuditLog.STRIPE_CUSTOMER_CREATED,
|
||||||
RealmAuditLog.STRIPE_CARD_ADDED,
|
RealmAuditLog.STRIPE_CARD_ADDED,
|
||||||
RealmAuditLog.STRIPE_CARD_ADDED,
|
RealmAuditLog.STRIPE_CARD_ADDED,
|
||||||
RealmAuditLog.STRIPE_PLAN_CHANGED])
|
RealmAuditLog.STRIPE_PLAN_CHANGED,
|
||||||
|
RealmAuditLog.REALM_PLAN_TYPE_CHANGED])
|
||||||
# Check that we correctly updated Realm
|
# Check that we correctly updated Realm
|
||||||
realm = get_realm("zulip")
|
realm = get_realm("zulip")
|
||||||
self.assertTrue(realm.has_seat_based_plan)
|
self.assertTrue(realm.has_seat_based_plan)
|
||||||
|
|||||||
@@ -123,3 +123,5 @@ if FAKE_LDAP_MODE:
|
|||||||
THUMBOR_URL = 'http://127.0.0.1:9995'
|
THUMBOR_URL = 'http://127.0.0.1:9995'
|
||||||
|
|
||||||
SEARCH_PILLS_ENABLED = os.getenv('SEARCH_PILLS_ENABLED', False)
|
SEARCH_PILLS_ENABLED = os.getenv('SEARCH_PILLS_ENABLED', False)
|
||||||
|
|
||||||
|
BILLING_ENABLED = True
|
||||||
|
|||||||
@@ -437,6 +437,10 @@ DEFAULT_SETTINGS.update({
|
|||||||
# DEFAULT_SETTINGS, since it likely isn't usefully user-configurable.
|
# DEFAULT_SETTINGS, since it likely isn't usefully user-configurable.
|
||||||
'OFFLINE_THRESHOLD_SECS': 5 * 60,
|
'OFFLINE_THRESHOLD_SECS': 5 * 60,
|
||||||
|
|
||||||
|
# Enables billing pages and plan-based feature gates. If False, all features
|
||||||
|
# are available to all realms.
|
||||||
|
'BILLING_ENABLED': False,
|
||||||
|
|
||||||
# Controls whether we run the worker that syncs billing-related updates
|
# Controls whether we run the worker that syncs billing-related updates
|
||||||
# into Stripe. Should be True on at most one machine.
|
# into Stripe. Should be True on at most one machine.
|
||||||
'BILLING_PROCESSOR_ENABLED': False,
|
'BILLING_PROCESSOR_ENABLED': False,
|
||||||
|
|||||||
Reference in New Issue
Block a user