free trial: Send users to /upgrade after realm creation.

This commit is contained in:
Vishnu KS 2020-05-22 19:12:46 +05:30 committed by Tim Abbott
parent a5f0379e0f
commit 8784539d53
12 changed files with 138 additions and 3 deletions

View File

@ -625,6 +625,11 @@ class StripeTest(StripeTestCase):
'Visa ending in 4242',
'Update card']:
self.assert_in_response(substring, response)
self.assert_not_in_success_response(["Go to your Zulip organization"], response)
with patch('corporate.views.timezone_now', return_value=self.now):
response = self.client_get("/billing/?onboarding=true")
self.assert_in_success_response(["Go to your Zulip organization"], response)
with patch('corporate.lib.stripe.get_latest_seat_count', return_value=12):
update_license_ledger_if_needed(realm, self.now)
@ -1053,6 +1058,33 @@ class StripeTest(StripeTestCase):
self.assertEqual(response.status_code, 302)
self.assertEqual('/upgrade/', response.url)
def test_redirect_for_upgrade_page(self) -> None:
user = self.example_user("iago")
self.login_user(user)
# No Customer yet;
response = self.client_get("/upgrade/")
self.assertEqual(response.status_code, 200)
# Customer, but no CustomerPlan;
customer = Customer.objects.create(realm=user.realm, stripe_customer_id='cus_123')
response = self.client_get("/upgrade/")
self.assertEqual(response.status_code, 200)
CustomerPlan.objects.create(customer=customer, billing_cycle_anchor=timezone_now(),
billing_schedule=CustomerPlan.ANNUAL, tier=CustomerPlan.STANDARD)
response = self.client_get("/upgrade/")
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/billing/")
with self.settings(FREE_TRIAL_DAYS=30):
response = self.client_get("/upgrade/")
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/billing/")
response = self.client_get("/upgrade/?onboarding=true")
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/billing/?onboarding=true")
def test_get_latest_seat_count(self) -> None:
realm = get_realm("zulip")
initial_count = get_latest_seat_count(realm)

View File

@ -129,7 +129,10 @@ def initial_upgrade(request: HttpRequest) -> HttpResponse:
user = request.user
customer = get_customer_by_realm(user.realm)
if customer is not None and get_current_plan_by_customer(customer) is not None:
return HttpResponseRedirect(reverse('corporate.views.billing_home'))
billing_page_url = reverse('corporate.views.billing_home')
if request.GET.get("onboarding") is not None:
billing_page_url = "{}?onboarding=true".format(billing_page_url)
return HttpResponseRedirect(billing_page_url)
percent_off = Decimal(0)
if customer is not None and customer.default_discount is not None:
@ -147,6 +150,7 @@ def initial_upgrade(request: HttpRequest) -> HttpResponse:
'default_invoice_days_until_due': DEFAULT_INVOICE_DAYS_UNTIL_DUE,
'plan': "Zulip Standard",
"free_trial_days": settings.FREE_TRIAL_DAYS,
"onboarding": request.GET.get("onboarding") is not None,
'page_params': {
'seat_count': seat_count,
'annual_price': 8000,
@ -212,6 +216,7 @@ def billing_home(request: HttpRequest) -> HttpResponse:
'publishable_key': STRIPE_PUBLISHABLE_KEY,
'stripe_email': stripe_customer.email,
'CustomerPlan': CustomerPlan,
'onboarding': request.GET.get("onboarding") is not None,
})
return render(request, 'corporate/billing.html', context=context)

View File

@ -25,6 +25,7 @@ run_test('create_ajax_request', () => {
const form_success = "#autopay-success";
const form_error = "#autopay-error";
const form_loading = "#autopay-loading";
const zulip_limited_section = "#zulip-limited-section";
const state = {
form_input_section_show: 0,
@ -34,6 +35,8 @@ run_test('create_ajax_request', () => {
form_loading_show: 0,
form_loading_hide: 0,
form_success_show: 0,
zulip_limited_section_show: 0,
zulip_limited_section_hide: 0,
location_reload: 0,
pushState: 0,
make_indicator: 0,
@ -79,6 +82,14 @@ run_test('create_ajax_request', () => {
state.form_loading_hide += 1;
};
$(zulip_limited_section).show = () => {
state.zulip_limited_section_show += 1;
};
$(zulip_limited_section).hide = () => {
state.zulip_limited_section_hide += 1;
};
$("#autopay-form").serializeArray = () => {
return jquery("#autopay-form").serializeArray();
};
@ -87,6 +98,8 @@ run_test('create_ajax_request', () => {
assert.equal(state.form_input_section_hide, 1);
assert.equal(state.form_error_hide, 1);
assert.equal(state.form_loading_show, 1);
assert.equal(state.zulip_limited_section_hide, 1);
assert.equal(state.zulip_limited_section_show, 0);
assert.equal(state.make_indicator, 1);
assert.equal(url, "/json/billing/upgrade");
@ -119,12 +132,15 @@ run_test('create_ajax_request', () => {
assert.equal(state.form_success_show, 1);
assert.equal(state.form_error_hide, 2);
assert.equal(state.form_loading_hide, 1);
assert.equal(state.zulip_limited_section_hide, 1);
assert.equal(state.zulip_limited_section_show, 0);
error({responseText: '{"msg": "response_message"}'});
assert.equal(state.form_loading_hide, 2);
assert.equal(state.form_error_show, 1);
assert.equal(state.form_input_section_show, 1);
assert.equal(state.zulip_limited_section_hide, 1);
};
helpers.create_ajax_request("/json/billing/upgrade", "autopay", {id: "stripe_token_id"}, ["licenses"]);

View File

@ -102,6 +102,7 @@ run_test("initialize", () => {
helpers.is_valid_input = () => {
return true;
};
add_card_click_handler(e);
invoice_click_handler(e);
@ -159,6 +160,8 @@ run_test("autopay_form_fields", () => {
assert(document.querySelector("#autopay_loading_indicator"));
assert(document.querySelector("input[name=csrfmiddlewaretoken]"));
assert(document.querySelector("#zulip-limited-section"));
});
run_test("invoice_form_fields", () => {
@ -178,4 +181,6 @@ run_test("invoice_form_fields", () => {
assert(document.querySelector("#invoice_loading_indicator"));
assert(document.querySelector("input[name=csrfmiddlewaretoken]"));
assert(document.querySelector("#zulip-limited-section"));
});

View File

@ -6,11 +6,16 @@ exports.create_ajax_request = function (url, form_name, stripe_token = null, num
const form_error = "#" + form_name + "-error";
const form_loading = "#" + form_name + "-loading";
const zulip_limited_section = "#zulip-limited-section";
const free_trial_alert_message = "#free-trial-alert-message";
loading.make_indicator($(form_loading_indicator),
{text: 'Processing ...', abs_positioned: true});
$(form_input_section).hide();
$(form_error).hide();
$(form_loading).show();
$(zulip_limited_section).hide();
$(free_trial_alert_message).hide();
const data = {};
if (stripe_token) {
@ -45,6 +50,8 @@ exports.create_ajax_request = function (url, form_name, stripe_token = null, num
$(form_loading).hide();
$(form_error).show().text(JSON.parse(xhr.responseText).msg);
$(form_input_section).show();
$(zulip_limited_section).show();
$(free_trial_alert_message).show();
},
});
};

View File

@ -124,6 +124,15 @@
<div class="tab-pane" id="loading">
</div>
</div>
<div id="goto-zulip-organization-link">
{% if onboarding %}
<br>
<h3>
<b><a href="/">Go to your Zulip organization</a></b>
</h3>
{% endif %}
</div>
<hr>
<div class="support-link">
<p>
Contact <a href="mailto:support@zulipchat.com">support@zulipchat.com</a>

View File

@ -207,6 +207,15 @@
</div>
</div>
</div>
{% if onboarding %}
<div id="zulip-limited-section">
<br>
<h3>
<b><a href="/">Or start with Zulip Limited (Free) plan</a></b>
</h3>
</div>
{% endif %}
<hr>
<div class="support-link">
<p>
We're happy to help!

View File

@ -2150,6 +2150,10 @@ class RealmCreationTest(ZulipTestCase):
HTTP_HOST=string_id + ".testserver")
self.assertEqual(result.status_code, 302)
result = self.client_get(result.url, subdomain=string_id)
self.assertEqual(result.status_code, 302)
self.assertEqual(result.url, 'http://zuliptest.testserver')
# Make sure the realm is created
realm = get_realm(string_id)
self.assertEqual(realm.string_id, string_id)
@ -2158,6 +2162,46 @@ class RealmCreationTest(ZulipTestCase):
self.assertEqual(realm.name, realm_name)
self.assertEqual(realm.subdomain, string_id)
@override_settings(OPEN_REALM_CREATION=True, FREE_TRIAL_DAYS=30)
def test_create_realm_during_free_trial(self) -> None:
password = "test"
string_id = "zuliptest"
email = "user1@test.com"
realm_name = "Test"
with self.assertRaises(Realm.DoesNotExist):
get_realm(string_id)
result = self.client_post('/new/', {'email': email})
self.assertEqual(result.status_code, 302)
self.assertTrue(result["Location"].endswith(
"/accounts/new/send_confirm/%s" % (email,)))
result = self.client_get(result["Location"])
self.assert_in_response("Check your email so we can get started.", result)
confirmation_url = self.get_confirmation_url_from_outbox(email)
result = self.client_get(confirmation_url)
self.assertEqual(result.status_code, 200)
result = self.submit_reg_form_for_user(email, password,
realm_subdomain = string_id,
realm_name=realm_name,
HTTP_HOST=string_id + ".testserver")
self.assertEqual(result.status_code, 302)
result = self.client_get(result.url, subdomain=string_id)
self.assertEqual(result.url, 'http://zuliptest.testserver/upgrade/?onboarding=true')
result = self.client_get(result.url, subdomain=string_id)
self.assert_in_success_response(["Or start with Zulip Limited (Free) plan"], result)
realm = get_realm(string_id)
self.assertEqual(realm.string_id, string_id)
self.assertEqual(get_user(email, realm).realm, realm)
self.assertEqual(realm.name, realm_name)
self.assertEqual(realm.subdomain, string_id)
@override_settings(OPEN_REALM_CREATION=True)
def test_mailinator_signup(self) -> None:
result = self.client_post('/new/', {'email': "hi@mailinator.com"})

View File

@ -218,6 +218,7 @@ def register_remote_user(request: HttpRequest, result: ExternalAuthResult) -> Ht
# maybe_send_to_registration doesn't take these arguments, so delete them.
kwargs.pop('subdomain', None)
kwargs.pop('redirect_to', None)
kwargs.pop('is_realm_creation', None)
kwargs["password_required"] = False
return maybe_send_to_registration(request, **kwargs)
@ -247,6 +248,7 @@ def login_or_register_remote_user(request: HttpRequest, result: ExternalAuthResu
# Otherwise, the user has successfully authenticated to an
# account, and we need to do the right thing depending whether
# or not they're using the mobile OTP flow or want a browser session.
is_realm_creation = result.data_dict.get('is_realm_creation')
mobile_flow_otp = result.data_dict.get('mobile_flow_otp')
desktop_flow_otp = result.data_dict.get('desktop_flow_otp')
if mobile_flow_otp is not None:
@ -256,7 +258,11 @@ def login_or_register_remote_user(request: HttpRequest, result: ExternalAuthResu
do_login(request, user_profile)
redirect_to = get_safe_redirect_to(result.data_dict.get('redirect_to', ''), user_profile.realm.uri)
redirect_to = result.data_dict.get('redirect_to', '')
if is_realm_creation is not None and settings.FREE_TRIAL_DAYS not in [None, 0]:
redirect_to = "{}?onboarding=true".format(reverse('corporate.views.initial_upgrade'))
redirect_to = get_safe_redirect_to(redirect_to, user_profile.realm.uri)
return HttpResponseRedirect(redirect_to)
def finish_desktop_flow(request: HttpRequest, user_profile: UserProfile,

View File

@ -343,7 +343,8 @@ def accounts_register(request: HttpRequest) -> HttpResponse:
# Because for realm creation, registration happens on the
# root domain, we need to log them into the subdomain for
# their new realm.
return redirect_and_log_into_subdomain(ExternalAuthResult(user_profile=user_profile))
return redirect_and_log_into_subdomain(ExternalAuthResult(user_profile=user_profile,
data_dict={'is_realm_creation': True}))
# This dummy_backend check below confirms the user is
# authenticating to the correct subdomain.

View File

@ -920,6 +920,7 @@ ExternalAuthDataDict = TypedDict('ExternalAuthDataDict', {
'full_name': str,
'email': str,
'is_signup': bool,
'is_realm_creation': bool,
'redirect_to': str,
'mobile_flow_otp': Optional[str],
'desktop_flow_otp': Optional[str],