diff --git a/corporate/urls.py b/corporate/urls.py index 4c291f7898..398d47c0d0 100644 --- a/corporate/urls.py +++ b/corporate/urls.py @@ -70,7 +70,13 @@ from corporate.views.sponsorship import ( sponsorship, sponsorship_page, ) -from corporate.views.support import demo_request, remote_servers_support, support, support_request +from corporate.views.support import ( + demo_request, + remote_servers_support, + sales_support_request, + support, + support_request, +) from corporate.views.upgrade import ( remote_realm_upgrade, remote_realm_upgrade_page, @@ -97,6 +103,7 @@ i18n_urlpatterns: Any = [ path("upgrade/", upgrade_page, name="upgrade_page"), path("support/", support_request), path("request-demo/", demo_request), + path("contact-sales/", sales_support_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 diff --git a/corporate/views/support.py b/corporate/views/support.py index 2b2338bafe..4b4fa726fa 100644 --- a/corporate/views/support.py +++ b/corporate/views/support.py @@ -22,7 +22,11 @@ from pydantic import AfterValidator, Json, NonNegativeInt from confirmation.models import Confirmation, confirmation_url from confirmation.settings import STATUS_USED -from corporate.lib.activity import format_optional_datetime, remote_installation_stats_link +from corporate.lib.activity import ( + format_optional_datetime, + realm_support_link, + remote_installation_stats_link, +) from corporate.lib.billing_types import BillingModality from corporate.models import CustomerPlan from zerver.actions.create_realm import do_change_realm_subdomain @@ -95,6 +99,13 @@ class DemoRequestForm(forms.Form): message = forms.CharField(widget=forms.Textarea) +class SalesRequestForm(forms.Form): + MAX_INPUT_LENGTH = 50 + organization_website = forms.URLField(required=True, assume_scheme="https") + expected_user_count = forms.CharField(max_length=MAX_INPUT_LENGTH) + message = forms.CharField(widget=forms.Textarea) + + @zulip_login_required @typed_endpoint_without_parameters def support_request(request: HttpRequest) -> HttpResponse: @@ -186,6 +197,59 @@ def demo_request(request: HttpRequest) -> HttpResponse: return response +@zulip_login_required +@typed_endpoint_without_parameters +def sales_support_request(request: HttpRequest) -> HttpResponse: + from corporate.lib.stripe import BILLING_SUPPORT_EMAIL + + assert request.user.is_authenticated + + if not request.user.is_realm_admin: + return render(request, "404.html", status=404) + + context = { + "MAX_INPUT_LENGTH": SalesRequestForm.MAX_INPUT_LENGTH, + "user_email": request.user.delivery_email, + "user_full_name": request.user.full_name, + } + + if request.POST: + post_data = request.POST.copy() + form = SalesRequestForm(post_data) + + if form.is_valid(): + rate_limit_request_by_ip(request, domain="sends_email_by_ip") + + email_context = { + "full_name": request.user.full_name, + "email": request.user.delivery_email, + "role": UserProfile.ROLE_ID_TO_API_NAME[request.user.role], + "organization_name": request.user.realm.name, + "organization_type": get_org_type_display_name(request.user.realm.org_type), + "organization_website": form.cleaned_data["organization_website"], + "expected_user_count": form.cleaned_data["expected_user_count"], + "message": form.cleaned_data["message"], + "support_link": realm_support_link(request.user.realm.string_id), + } + + send_email( + "zerver/emails/sales_support_request", + to_emails=[BILLING_SUPPORT_EMAIL], + from_name="Sales support 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/sales_support_request.html", context=context) + return response + + def get_plan_type_string(plan_type: int) -> str: return { Realm.PLAN_TYPE_SELF_HOSTED: "Self-hosted", diff --git a/templates/corporate/support/sales_support_request.html b/templates/corporate/support/sales_support_request.html new file mode 100644 index 0000000000..b85785d9c4 --- /dev/null +++ b/templates/corporate/support/sales_support_request.html @@ -0,0 +1,51 @@ +{% extends "zerver/portico_signup.html" %} + +{% set PAGE_TITLE = "Contact sales | Zulip" %} + +{% block portico_content %} +
+
+
+

Contact sales

+
+ +
+ {{ csrf_input }} + +
+
+ +
+ {{ user_full_name }} ({{ user_email }}) +
+
+
+ + +
+
+ + +
+
+ + +
+ +
+ +
+
+
+ Your message will be sent to Zulip Sales. +
+
+
+
+
+
+ +{% endblock %} diff --git a/templates/zerver/emails/sales_support_request.html b/templates/zerver/emails/sales_support_request.html new file mode 100644 index 0000000000..63e35981f9 --- /dev/null +++ b/templates/zerver/emails/sales_support_request.html @@ -0,0 +1,23 @@ +{% extends "zerver/emails/email_base_messages.html" %} + +{% block content %} +Subject: Sales support 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 }} +
+Support link: {{ support_link }} +
+ +{% endblock %} diff --git a/templates/zerver/emails/sales_support_request.subject.txt b/templates/zerver/emails/sales_support_request.subject.txt new file mode 100644 index 0000000000..116f6ffda6 --- /dev/null +++ b/templates/zerver/emails/sales_support_request.subject.txt @@ -0,0 +1 @@ +Sales support request for {{organization_name}} diff --git a/templates/zerver/emails/sales_support_request.txt b/templates/zerver/emails/sales_support_request.txt new file mode 100644 index 0000000000..a21202d52a --- /dev/null +++ b/templates/zerver/emails/sales_support_request.txt @@ -0,0 +1,17 @@ +Subject: Sales support 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 }} + +Support link: {{ support_link }} diff --git a/web/shared/icons/handshake.svg b/web/shared/icons/handshake.svg new file mode 100644 index 0000000000..573f50d70c --- /dev/null +++ b/web/shared/icons/handshake.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/src/navbar_help_menu.ts b/web/src/navbar_help_menu.ts index a5bccb9f85..6364c2732a 100644 --- a/web/src/navbar_help_menu.ts +++ b/web/src/navbar_help_menu.ts @@ -4,6 +4,7 @@ import render_navbar_help_menu from "../templates/popovers/navbar/navbar_help_me import {page_params} from "./page_params.ts"; import * as popover_menus from "./popover_menus.ts"; +import {current_user} from "./state_data.ts"; import {parse_html} from "./ui_util.ts"; export function initialize(): void { @@ -33,6 +34,8 @@ export function initialize(): void { parse_html( render_navbar_help_menu({ corporate_enabled: page_params.corporate_enabled, + is_owner: current_user.is_owner, + is_admin: current_user.is_admin, }), ), ); diff --git a/web/styles/portico/portico_signin.css b/web/styles/portico/portico_signin.css index 2b48fb8532..190af1fcf7 100644 --- a/web/styles/portico/portico_signin.css +++ b/web/styles/portico/portico_signin.css @@ -1461,3 +1461,12 @@ button#register_auth_button_gitlab { margin-top: 5px; display: none; } + +#sales-support-form-bottom-info { + padding: 0; + + .not-editable-realm-field { + margin: 0; + padding: 0; + } +} diff --git a/web/templates/popovers/navbar/navbar_help_menu_popover.hbs b/web/templates/popovers/navbar/navbar_help_menu_popover.hbs index 0b894d8dc3..5e4a1c6d2d 100644 --- a/web/templates/popovers/navbar/navbar_help_menu_popover.hbs +++ b/web/templates/popovers/navbar/navbar_help_menu_popover.hbs @@ -38,6 +38,14 @@ {{t 'Contact support' }} + {{#if (or is_admin is_owner)}} + + {{/if}} {{/if}}