demo_request: Add form for user to request a demo.

This sends an email to us after user fills out and sends the form.
This commit is contained in:
Aman Agrawal 2024-04-24 05:08:30 +00:00 committed by Tim Abbott
parent 0ab7233ffa
commit 263d1ae38e
9 changed files with 193 additions and 2 deletions

View File

@ -2344,6 +2344,37 @@ class StripeTest(StripeTestCase):
response,
)
def test_demo_request(self) -> None:
result = self.client_get("/request-demo/")
self.assertEqual(result.status_code, 200)
self.assert_in_success_response(["Request a demo"], result)
data = {
"full_name": "King Hamlet",
"email": "test@zulip.com",
"role": "Manager",
"organization_name": "Zulip",
"organization_type": "Business",
"organization_website": "https://example.com",
"expected_user_count": "10 (2 unpaid members)",
"message": "Need help!",
}
result = self.client_post("/request-demo/", data)
self.assert_in_success_response(["Thanks for contacting us!"], result)
from django.core.mail import outbox
self.assert_length(outbox, 1)
for message in outbox:
self.assert_length(message.to, 1)
self.assertEqual(message.to[0], "desdemona+admin@zulip.com")
self.assertEqual(message.subject, "Demo request for Zulip")
self.assertEqual(message.reply_to, ["test@zulip.com"])
self.assertEqual(self.email_envelope_from(message), settings.NOREPLY_EMAIL_ADDRESS)
self.assertIn("Zulip demo request <noreply-", self.email_display_from(message))
self.assertIn("Full name: King Hamlet", message.body)
def test_support_request(self) -> None:
user = self.example_user("hamlet")
self.assertIsNone(get_customer_by_realm(user.realm))

View File

@ -68,7 +68,7 @@ from corporate.views.sponsorship import (
sponsorship,
sponsorship_page,
)
from corporate.views.support import remote_servers_support, support, support_request
from corporate.views.support import demo_request, remote_servers_support, support, support_request
from corporate.views.upgrade import (
remote_realm_upgrade,
remote_realm_upgrade_page,
@ -94,6 +94,7 @@ i18n_urlpatterns: Any = [
path("sponsorship/", sponsorship_page, name="sponsorship_request"),
path("upgrade/", upgrade_page, name="upgrade_page"),
path("support/", support_request),
path("request-demo/", demo_request),
path("billing/event_status/", event_status_page, name="event_status_page"),
path("stripe/webhook/", stripe_webhook, name="stripe_webhook"),
# Server admin (user_profile.is_staff) visible stats pages

View File

@ -95,6 +95,21 @@ class SupportRequestForm(forms.Form):
request_message = forms.CharField(widget=forms.Textarea)
class DemoRequestForm(forms.Form):
MAX_INPUT_LENGTH = 50
SORTED_ORG_TYPE_NAMES = sorted(
([org_type["name"] for org_type in Realm.ORG_TYPES.values() if not org_type["hidden"]]),
)
full_name = forms.CharField(max_length=MAX_INPUT_LENGTH)
email = forms.EmailField()
role = forms.CharField(max_length=MAX_INPUT_LENGTH)
organization_name = forms.CharField(max_length=MAX_INPUT_LENGTH)
organization_type = forms.CharField()
organization_website = forms.URLField(required=True)
expected_user_count = forms.CharField(max_length=MAX_INPUT_LENGTH)
message = forms.CharField(widget=forms.Textarea)
@zulip_login_required
@has_request_variables
def support_request(request: HttpRequest) -> HttpResponse:
@ -139,6 +154,47 @@ def support_request(request: HttpRequest) -> HttpResponse:
return response
@has_request_variables
def demo_request(request: HttpRequest) -> HttpResponse:
context = {
"MAX_INPUT_LENGTH": DemoRequestForm.MAX_INPUT_LENGTH,
"SORTED_ORG_TYPE_NAMES": DemoRequestForm.SORTED_ORG_TYPE_NAMES,
}
if request.POST:
post_data = request.POST.copy()
form = DemoRequestForm(post_data)
if form.is_valid():
email_context = {
"full_name": form.cleaned_data["full_name"],
"email": form.cleaned_data["email"],
"role": form.cleaned_data["role"],
"organization_name": form.cleaned_data["organization_name"],
"organization_type": form.cleaned_data["organization_type"],
"organization_website": form.cleaned_data["organization_website"],
"expected_user_count": form.cleaned_data["expected_user_count"],
"message": form.cleaned_data["message"],
}
# Sent to the server's support team, so this email is not user-facing.
send_email(
"zerver/emails/demo_request",
to_emails=[FromAddress.SUPPORT],
from_name="Zulip demo request",
from_address=FromAddress.tokenized_no_reply_address(),
reply_to_email=email_context["email"],
context=email_context,
)
response = render(
request, "corporate/support/support_request_thanks.html", context=context
)
return response
response = render(request, "corporate/support/demo_request.html", context=context)
return response
def get_plan_type_string(plan_type: int) -> str:
return {
Realm.PLAN_TYPE_SELF_HOSTED: "Self-hosted",

View File

@ -0,0 +1,65 @@
{% extends "zerver/portico_signup.html" %}
{% block portico_content %}
<div class="register-account flex full-page">
<div class="center-block new-style">
<div class="pitch">
<h1>Request a demo</h1>
</div>
<form method="post" class="white-box" id="registration">
{{ csrf_input }}
<fieldset class="support-request">
<div class="input-box support-form-field">
<label for="full_name" class="inline-block label-title">Full name</label>
<input class="required" type="text" name="full_name" maxlength="{{ MAX_INPUT_LENGTH }}" required />
</div>
<div class="input-box support-form-field">
<label for="email" class="inline-block label-title">Email</label>
<input class="required" type="email" name="email" required />
</div>
<div class="input-box support-form-field">
<label for="role" class="inline-block label-title">Your role</label>
<input class="required" type="text" name="role" maxlength="{{ MAX_INPUT_LENGTH }}" required />
</div>
<div class="input-box support-form-field">
<label for="organization_name" class="inline-block label-title">Organization name</label>
<input class="required" type="text" name="organization_name" maxlength="{{ MAX_INPUT_LENGTH }}" required />
</div>
<div class="input-box support-form-field">
<label for="organization_type" class="inline-block label-title">Organization type</label>
<select name="organization_type" class="required">
{% for org_type in SORTED_ORG_TYPE_NAMES %}
<option
value="{{ org_type }}">
{{ org_type }}
</option>
{% endfor %}
</select>
</div>
<div class="input-box support-form-field">
<label for="organization_website" class="inline-block label-title">Organization website</label>
<input class="required" type="url" name="organization_website" required />
</div>
<div class="input-box support-form-field">
<label for="expected_user_count" class="inline-block label-title">Expected number of users (approximate range)</label>
<input class="required" type="text" name="expected_user_count" maxlength="{{ MAX_INPUT_LENGTH }}" required />
</div>
<div class="input-box support-form-field">
<label for="message" class="inline-block label-title">How can we help?</label>
<textarea name="message" cols="100" rows="5" required></textarea>
</div>
<div class="register-button-box">
<button class="register-button support-submit-button" type="submit">
<span>Submit</span>
<object class="loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
</div>
</fieldset>
</form>
</div>
</div>
{% endblock %}

View File

@ -6,7 +6,7 @@
{% block portico_content %}
<div class="flex full-page thanks-page">
<div class="center-block new-style">
<div class="center-block new-style white-box">
<h1>{{ _("Thanks for contacting us!") }}</h1>
<p>{{ _("We will be in touch with you soon.") }}</p>
<p>

View File

@ -0,0 +1,21 @@
{% extends "zerver/emails/email_base_messages.html" %}
{% block content %}
<b>Subject</b>: Demo request for {{ organization_name }}
<br />
<b>Full name</b>: {{ full_name }}
<br />
<b>Email</b>: {{ email }}
<br />
<b>Role</b>: {{ role }}
<br />
<b>Organization type</b>: {{ organization_type }}
<br />
<b>Organization website</b>: {{ organization_website }}
<br />
<b>Expected user count</b>: {{ expected_user_count }}
<br />
<b>Message</b>: {{ message }}
<br />
{% endblock %}

View File

@ -0,0 +1 @@
Demo request for {{organization_name}}

View File

@ -0,0 +1,15 @@
Subject: Demo request for {{ organization_name }}
Full name: {{ full_name }}
Email: {{ email }}
Role: {{ role }}
Organization type: {{ organization_type }}
Organization website: {{ organization_website }}
Expected user count: {{ expected_user_count }}
Message: {{ message }}

View File

@ -527,6 +527,7 @@ html {
input[type="email"],
input[type="password"],
input[type="number"],
input[type="url"],
textarea,
select {
padding: 10px 32px 10px 12px;