mirror of https://github.com/zulip/zulip.git
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:
parent
0ab7233ffa
commit
263d1ae38e
|
@ -2344,6 +2344,37 @@ class StripeTest(StripeTestCase):
|
||||||
response,
|
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:
|
def test_support_request(self) -> None:
|
||||||
user = self.example_user("hamlet")
|
user = self.example_user("hamlet")
|
||||||
self.assertIsNone(get_customer_by_realm(user.realm))
|
self.assertIsNone(get_customer_by_realm(user.realm))
|
||||||
|
|
|
@ -68,7 +68,7 @@ from corporate.views.sponsorship import (
|
||||||
sponsorship,
|
sponsorship,
|
||||||
sponsorship_page,
|
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 (
|
from corporate.views.upgrade import (
|
||||||
remote_realm_upgrade,
|
remote_realm_upgrade,
|
||||||
remote_realm_upgrade_page,
|
remote_realm_upgrade_page,
|
||||||
|
@ -94,6 +94,7 @@ i18n_urlpatterns: Any = [
|
||||||
path("sponsorship/", sponsorship_page, name="sponsorship_request"),
|
path("sponsorship/", sponsorship_page, name="sponsorship_request"),
|
||||||
path("upgrade/", upgrade_page, name="upgrade_page"),
|
path("upgrade/", upgrade_page, name="upgrade_page"),
|
||||||
path("support/", support_request),
|
path("support/", support_request),
|
||||||
|
path("request-demo/", demo_request),
|
||||||
path("billing/event_status/", event_status_page, name="event_status_page"),
|
path("billing/event_status/", event_status_page, name="event_status_page"),
|
||||||
path("stripe/webhook/", stripe_webhook, name="stripe_webhook"),
|
path("stripe/webhook/", stripe_webhook, name="stripe_webhook"),
|
||||||
# Server admin (user_profile.is_staff) visible stats pages
|
# Server admin (user_profile.is_staff) visible stats pages
|
||||||
|
|
|
@ -95,6 +95,21 @@ class SupportRequestForm(forms.Form):
|
||||||
request_message = forms.CharField(widget=forms.Textarea)
|
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
|
@zulip_login_required
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def support_request(request: HttpRequest) -> HttpResponse:
|
def support_request(request: HttpRequest) -> HttpResponse:
|
||||||
|
@ -139,6 +154,47 @@ def support_request(request: HttpRequest) -> HttpResponse:
|
||||||
return response
|
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:
|
def get_plan_type_string(plan_type: int) -> str:
|
||||||
return {
|
return {
|
||||||
Realm.PLAN_TYPE_SELF_HOSTED: "Self-hosted",
|
Realm.PLAN_TYPE_SELF_HOSTED: "Self-hosted",
|
||||||
|
|
|
@ -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 %}
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
{% block portico_content %}
|
{% block portico_content %}
|
||||||
<div class="flex full-page thanks-page">
|
<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>
|
<h1>{{ _("Thanks for contacting us!") }}</h1>
|
||||||
<p>{{ _("We will be in touch with you soon.") }}</p>
|
<p>{{ _("We will be in touch with you soon.") }}</p>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -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 %}
|
|
@ -0,0 +1 @@
|
||||||
|
Demo request for {{organization_name}}
|
|
@ -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 }}
|
|
@ -527,6 +527,7 @@ html {
|
||||||
input[type="email"],
|
input[type="email"],
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
input[type="number"],
|
input[type="number"],
|
||||||
|
input[type="url"],
|
||||||
textarea,
|
textarea,
|
||||||
select {
|
select {
|
||||||
padding: 10px 32px 10px 12px;
|
padding: 10px 32px 10px 12px;
|
||||||
|
|
Loading…
Reference in New Issue