mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	corporate: Add contact support page.
This commit is contained in:
		
							
								
								
									
										15
									
								
								corporate/lib/support.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								corporate/lib/support.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
from urllib.parse import urlencode, urljoin, urlunsplit
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
 | 
			
		||||
from zerver.models import Realm, get_realm
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_support_url(realm: Realm) -> str:
 | 
			
		||||
    support_realm_uri = get_realm(settings.STAFF_SUBDOMAIN).uri
 | 
			
		||||
    support_url = urljoin(
 | 
			
		||||
        support_realm_uri,
 | 
			
		||||
        urlunsplit(("", "", reverse("support"), urlencode({"q": realm.string_id}), "")),
 | 
			
		||||
    )
 | 
			
		||||
    return support_url
 | 
			
		||||
@@ -1487,6 +1487,41 @@ class StripeTest(StripeTestCase):
 | 
			
		||||
 | 
			
		||||
        self.assert_json_success(response)
 | 
			
		||||
 | 
			
		||||
    def test_support_request(self) -> None:
 | 
			
		||||
        user = self.example_user("hamlet")
 | 
			
		||||
        self.assertIsNone(get_customer_by_realm(user.realm))
 | 
			
		||||
 | 
			
		||||
        self.login_user(user)
 | 
			
		||||
 | 
			
		||||
        result = self.client_get("/support/")
 | 
			
		||||
        self.assertEqual(result.status_code, 200)
 | 
			
		||||
        self.assert_in_success_response(["Contact support"], result)
 | 
			
		||||
 | 
			
		||||
        data = {
 | 
			
		||||
            "request_subject": "Not getting messages.",
 | 
			
		||||
            "request_message": "Running into this weird issue.",
 | 
			
		||||
        }
 | 
			
		||||
        result = self.client_post("/support/", data)
 | 
			
		||||
        self.assert_in_success_response(["Thanks for getting in touch with 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, "Support request for zulip")
 | 
			
		||||
            self.assertEqual(message.reply_to, ["hamlet@zulip.com"])
 | 
			
		||||
            self.assertEqual(self.email_envelope_from(message), settings.NOREPLY_EMAIL_ADDRESS)
 | 
			
		||||
            self.assertIn("Zulip Support <noreply-", self.email_display_from(message))
 | 
			
		||||
            self.assertIn("Requested by: King Hamlet (Member)", message.body)
 | 
			
		||||
            self.assertIn(
 | 
			
		||||
                "Support URL: http://zulip.testserver/activity/support?q=zulip", message.body
 | 
			
		||||
            )
 | 
			
		||||
            self.assertIn("Subject: Not getting messages.", message.body)
 | 
			
		||||
            self.assertIn("Message:\nRunning into this weird issue", message.body)
 | 
			
		||||
 | 
			
		||||
    def test_request_sponsorship(self) -> None:
 | 
			
		||||
        user = self.example_user("hamlet")
 | 
			
		||||
        self.assertIsNone(get_customer_by_realm(user.realm))
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ from django.urls import path
 | 
			
		||||
from django.views.generic import TemplateView
 | 
			
		||||
 | 
			
		||||
from corporate.views.billing_page import billing_home, replace_payment_source, update_plan
 | 
			
		||||
from corporate.views.support import support_request
 | 
			
		||||
from corporate.views.upgrade import initial_upgrade, sponsorship, upgrade
 | 
			
		||||
from zerver.lib.rest import rest_path
 | 
			
		||||
 | 
			
		||||
@@ -16,6 +17,7 @@ i18n_urlpatterns: Any = [
 | 
			
		||||
    # Billing
 | 
			
		||||
    path("billing/", billing_home),
 | 
			
		||||
    path("upgrade/", initial_upgrade, name="initial_upgrade"),
 | 
			
		||||
    path("support/", support_request),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
v1_api_and_json_patterns = [
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								corporate/views/support.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								corporate/views/support.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
from django import forms
 | 
			
		||||
from django.http import HttpRequest, HttpResponse
 | 
			
		||||
from django.shortcuts import render
 | 
			
		||||
 | 
			
		||||
from corporate.lib.support import get_support_url
 | 
			
		||||
from zerver.decorator import zulip_login_required
 | 
			
		||||
from zerver.lib.request import has_request_variables
 | 
			
		||||
from zerver.lib.send_email import FromAddress, send_email
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SupportRequestForm(forms.Form):
 | 
			
		||||
    # We use the same subject length requirement as GitHub's
 | 
			
		||||
    # contact support form.
 | 
			
		||||
    MAX_SUBJECT_LENGTH = 50
 | 
			
		||||
    request_subject = forms.CharField(max_length=MAX_SUBJECT_LENGTH)
 | 
			
		||||
    request_message = forms.CharField(widget=forms.Textarea)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@zulip_login_required
 | 
			
		||||
@has_request_variables
 | 
			
		||||
def support_request(request: HttpRequest) -> HttpResponse:
 | 
			
		||||
    user = request.user
 | 
			
		||||
    assert user.is_authenticated
 | 
			
		||||
 | 
			
		||||
    context = {
 | 
			
		||||
        "email": user.delivery_email,
 | 
			
		||||
        "realm_name": user.realm.name,
 | 
			
		||||
        "MAX_SUBJECT_LENGTH": SupportRequestForm.MAX_SUBJECT_LENGTH,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if request.POST:
 | 
			
		||||
        post_data = request.POST.copy()
 | 
			
		||||
        form = SupportRequestForm(post_data)
 | 
			
		||||
 | 
			
		||||
        if form.is_valid():
 | 
			
		||||
            email_context = {
 | 
			
		||||
                "requested_by": user.full_name,
 | 
			
		||||
                "realm_string_id": user.realm.string_id,
 | 
			
		||||
                "request_subject": form.cleaned_data["request_subject"],
 | 
			
		||||
                "request_message": form.cleaned_data["request_message"],
 | 
			
		||||
                "support_url": get_support_url(user.realm),
 | 
			
		||||
                "user_role": user.get_role_name(),
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            send_email(
 | 
			
		||||
                "zerver/emails/support_request",
 | 
			
		||||
                to_emails=[FromAddress.SUPPORT],
 | 
			
		||||
                from_name="Zulip Support",
 | 
			
		||||
                from_address=FromAddress.tokenized_no_reply_address(),
 | 
			
		||||
                reply_to_email=user.delivery_email,
 | 
			
		||||
                context=email_context,
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            response = render(request, "corporate/support_request_thanks.html", context=context)
 | 
			
		||||
            return response
 | 
			
		||||
 | 
			
		||||
    response = render(request, "corporate/support_request.html", context=context)
 | 
			
		||||
    return response
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
import logging
 | 
			
		||||
from decimal import Decimal
 | 
			
		||||
from typing import Any, Dict, Optional
 | 
			
		||||
from urllib.parse import urlencode, urljoin, urlunsplit
 | 
			
		||||
 | 
			
		||||
from django import forms
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
@@ -24,6 +23,7 @@ from corporate.lib.stripe import (
 | 
			
		||||
    update_sponsorship_status,
 | 
			
		||||
    validate_licenses,
 | 
			
		||||
)
 | 
			
		||||
from corporate.lib.support import get_support_url
 | 
			
		||||
from corporate.models import (
 | 
			
		||||
    CustomerPlan,
 | 
			
		||||
    ZulipSponsorshipRequest,
 | 
			
		||||
@@ -37,7 +37,7 @@ from zerver.lib.request import REQ, has_request_variables
 | 
			
		||||
from zerver.lib.response import json_success
 | 
			
		||||
from zerver.lib.send_email import FromAddress, send_email
 | 
			
		||||
from zerver.lib.validator import check_bool, check_int, check_string_in
 | 
			
		||||
from zerver.models import Realm, UserProfile, get_org_type_display_name, get_realm
 | 
			
		||||
from zerver.models import Realm, UserProfile, get_org_type_display_name
 | 
			
		||||
 | 
			
		||||
billing_logger = logging.getLogger("corporate.stripe")
 | 
			
		||||
 | 
			
		||||
@@ -221,12 +221,7 @@ def sponsorship(
 | 
			
		||||
 | 
			
		||||
    requested_by = user.full_name
 | 
			
		||||
    user_role = user.get_role_name()
 | 
			
		||||
 | 
			
		||||
    support_realm_uri = get_realm(settings.STAFF_SUBDOMAIN).uri
 | 
			
		||||
    support_url = urljoin(
 | 
			
		||||
        support_realm_uri,
 | 
			
		||||
        urlunsplit(("", "", reverse("support"), urlencode({"q": realm.string_id}), "")),
 | 
			
		||||
    )
 | 
			
		||||
    support_url = get_support_url(realm)
 | 
			
		||||
 | 
			
		||||
    post_data = request.POST.copy()
 | 
			
		||||
    # We need to do this because the field name in the template
 | 
			
		||||
 
 | 
			
		||||
@@ -286,6 +286,10 @@ html {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thanks-page div {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.lead {
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -417,6 +417,7 @@ html {
 | 
			
		||||
        input[type="text"],
 | 
			
		||||
        input[type="email"],
 | 
			
		||||
        input[type="password"],
 | 
			
		||||
        textarea,
 | 
			
		||||
        select {
 | 
			
		||||
            padding: 10px 32px 10px 12px;
 | 
			
		||||
            margin: 25px 0 5px;
 | 
			
		||||
@@ -815,6 +816,16 @@ button#register_auth_button_gitlab {
 | 
			
		||||
                margin-left: 2px;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &.support-form-field {
 | 
			
		||||
            width: 450px;
 | 
			
		||||
 | 
			
		||||
            input,
 | 
			
		||||
            textarea {
 | 
			
		||||
                width: 400px;
 | 
			
		||||
                font-size: 1rem;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & [for="realm_in_root_domain"] {
 | 
			
		||||
@@ -831,6 +842,12 @@ button#register_auth_button_gitlab {
 | 
			
		||||
        border-radius: 4px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .support-submit-button {
 | 
			
		||||
        margin-top: 20px;
 | 
			
		||||
        margin-bottom: 5px;
 | 
			
		||||
        width: 450px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .register-button .loader {
 | 
			
		||||
        display: none;
 | 
			
		||||
        vertical-align: top;
 | 
			
		||||
@@ -868,7 +885,9 @@ button#register_auth_button_gitlab {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #id_email {
 | 
			
		||||
    #id_email,
 | 
			
		||||
    #support_from,
 | 
			
		||||
    #support_realm {
 | 
			
		||||
        font-weight: normal;
 | 
			
		||||
        margin: 2px;
 | 
			
		||||
        padding-top: 25px;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										43
									
								
								templates/corporate/support_request.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								templates/corporate/support_request.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
{% 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>{{ _('Contact support') }}</h1>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <form method="post" class="form-horizontal white-box" id="registration">
 | 
			
		||||
            {{ csrf_input }}
 | 
			
		||||
 | 
			
		||||
            <fieldset class="support-request">
 | 
			
		||||
                <div class="input-box no-validation support-form-field">
 | 
			
		||||
                    <label for="support_from" class="inline-block label-title">{{ _('From') }}</label>
 | 
			
		||||
                    <div id="support_from">{{ email }}</div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="input-box no-validation support-form-field">
 | 
			
		||||
                    <label for="support_realm" class="inline-block label-title">{{ _('Organization') }}</label>
 | 
			
		||||
                    <div id="support_realm">{{ realm_name }}</div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="input-box support-form-field">
 | 
			
		||||
                    <label for="request_subject" class="inline-block label-title">{{ _('Subject') }}</label>
 | 
			
		||||
                    <input id="request_subject" class="required" type="text" name="request_subject" maxlength="{{ MAX_SUBJECT_LENGTH }}" required />
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="input-box support-form-field">
 | 
			
		||||
                    <label for="request_message" class="inline-block label-title">{{ _('Message') }}</label>
 | 
			
		||||
                    <textarea id="request_message" name="request_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/loader-white.svg"></object>
 | 
			
		||||
                    </button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </fieldset>
 | 
			
		||||
        </form>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								templates/corporate/support_request_thanks.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								templates/corporate/support_request_thanks.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
{% extends "zerver/portico.html" %}
 | 
			
		||||
 | 
			
		||||
{% block portico_content %}
 | 
			
		||||
<div class="flex full-page thanks-page">
 | 
			
		||||
    <div class="center-block new-style">
 | 
			
		||||
        <h1>Thanks for contacting us!</h1>
 | 
			
		||||
        <p>We will be in touch with you soon.</p>
 | 
			
		||||
        <p>
 | 
			
		||||
            You can find answers to frequently asked questions in the
 | 
			
		||||
            <a href="/help/">Zulip help center</a>.
 | 
			
		||||
        </p>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										21
									
								
								templates/zerver/emails/support_request.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								templates/zerver/emails/support_request.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
{% extends "zerver/emails/email_base_messages.html" %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<b>Support URL</b>: <a href="{{ support_url }}">{{ support_url }}</a>
 | 
			
		||||
 | 
			
		||||
<br /><br />
 | 
			
		||||
 | 
			
		||||
<b>Subject</b>: {{ request_subject }}
 | 
			
		||||
 | 
			
		||||
<br /><br />
 | 
			
		||||
 | 
			
		||||
<b>Message</b>:
 | 
			
		||||
<br />
 | 
			
		||||
{{ request_message }}
 | 
			
		||||
 | 
			
		||||
<br /><br />
 | 
			
		||||
 | 
			
		||||
<b>Requested by</b>: {{ requested_by }} ({{ user_role }})
 | 
			
		||||
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								templates/zerver/emails/support_request.subject.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								templates/zerver/emails/support_request.subject.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
Support request for {{ realm_string_id }}
 | 
			
		||||
							
								
								
									
										8
									
								
								templates/zerver/emails/support_request.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								templates/zerver/emails/support_request.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
Support URL: {{ support_url }}
 | 
			
		||||
 | 
			
		||||
Subject: {{ request_subject }}
 | 
			
		||||
 | 
			
		||||
Message:
 | 
			
		||||
{{ request_message }}
 | 
			
		||||
 | 
			
		||||
Requested by: {{ requested_by }} ({{ user_role }})
 | 
			
		||||
@@ -547,6 +547,9 @@ html_rules: List["Rule"] = [
 | 
			
		||||
            "templates/zerver/email.html",
 | 
			
		||||
            "zerver/tests/fixtures/email",
 | 
			
		||||
            "templates/zerver/for-companies.html",
 | 
			
		||||
            "templates/corporate/support_request.html",
 | 
			
		||||
            "templates/corporate/support_request_thanks.html",
 | 
			
		||||
            "templates/zerver/emails/support_request.html",
 | 
			
		||||
        },
 | 
			
		||||
        "exclude_pattern": "email subject",
 | 
			
		||||
        "description": "avoid subject in templates",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user