snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-15 15:05:30 +05:00
commit 64898b2c79
8999 changed files with 1757358 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
{% extends "zerver/portico_signup.html" %}
{% block title %}
<title>{{ _("Accept the Terms of Service") }} | Zulip</title>
{% endblock %}
{#
Allow the user to accept a TOS, creating an email record of that fact.
Users only hit this page if they are coming from a migration or other update of the TOS;
the registration flow has its own (nearly identical) copy of the fields below in register.html.
#}
{% block portico_content %}
<div class="account-accept-terms-page flex full-page">
<div class="center-block new-style">
<div class="pitch">
<h1 class="get-started">{{ _("Welcome to Zulip") }}</h1>
</div>
<div class="white-box">
<form method="post" id="registration" action="{{ url('accept_terms') }}">
{{ csrf_input }}
<div id="registration-email">
<label for="id_email">{{ _("Email") }}</label>
<div class="controls fakecontrol">{{ email }}</div>
{% if first_time_login %}
{% include 'zerver/create_user/new_user_email_address_visibility.html' %}
{% endif %}
</div>
{% if first_time_terms_of_service_message_template %}
{% include first_time_terms_of_service_message_template %}
{% elif terms_of_service_message %}
<div class="description">
<p>{{ terms_of_service_message |safe }}</p>
</div>
{% endif %}
{% if terms_of_service %}
{% include 'zerver/create_user/terms_of_service_form_field.html' %}
{% if first_time_terms_of_service_message_template %}
<div class="input-group">
<label for="id_enable_marketing_emails_first_login" class="inline-block checkbox marketing_emails_checkbox">
<input id="id_enable_marketing_emails_first_login" type="checkbox" name="enable_marketing_emails"
checked="checked" />
<span class="rendered-checkbox"></span>
{% trans %}Subscribe me to Zulip's low-traffic newsletter (a few emails a year).{% endtrans %}
</label>
</div>
{% endif %}
{% endif %}
<div class="controls">
<button id="accept_tos_button" type="submit">{{ _('Continue') }}</button>
<input type="hidden" name="next" value="{{ next }}" />
</div>
</form>
</div>
</div>
</div>
{% if first_time_login %}
{% include 'zerver/create_user/change_email_address_visibility_modal.html' %}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,50 @@
{% extends "zerver/portico_signup.html" %}
{# Displayed after a user attempts to sign up. #}
{% block title %}
<title>{{ _("Confirm your email address") }} | Zulip</title>
{% endblock %}
{% block portico_content %}
<!-- The following empty tag has unique data-page-id so that this
page can be easily identified in it's respective JavaScript file -->
<div data-page-id="accounts-send-confirm"></div>
<div class="app portico-page">
<div class="app-main portico-page-container center-block flex full-page account-creation account-email-confirm-container new-style">
<div class="inline-block">
<div class="get-started">
<h1>{{ _("Confirm your email address") }}</h1>
</div>
<div class="white-box">
<p>{% trans %}To complete your registration, check your email account (<span class="user_email semi-bold">{{ email }}</span>) for a confirmation email from Zulip.{% endtrans %}</p>
{% include 'zerver/dev_env_email_access_details.html' %}
<p>{% trans %}If you don't see a confirmation email in your Inbox or Spam folder, we can <a href="#" id="resend_email_link">resend it</a>.{% endtrans %}
</p>
{% if realm_creation %}
<form class="resend_confirm" action="/new/" method="post" style="position: absolute;">
{{ csrf_input }}
<input type="hidden" class="email" id="email" value="{{ email }}" name="email"/>&nbsp;
<input type="hidden" class="realm_name" value="{{ new_realm_name }}" name="realm_name"/>&nbsp;
<input type="hidden" class="realm_type" value="{{ realm_type }}" name="realm_type"/>&nbsp;
<input type="hidden" class="realm_default_language" value="{{ realm_default_language }}" name="realm_default_language"/>&nbsp;
<input type="hidden" class="realm_subdomain" value="{{ realm_subdomain }}" name="realm_subdomain"/>&nbsp;
</form>
{% else %}
<form class="resend_confirm" action="/accounts/home/" method="post" style="position: absolute;">
{{ csrf_input }}
<input type="hidden" class="email" id="email" value="{{ email }}" name="email"/>&nbsp;
</form>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block customhead %}
{{ super() }}
{% endblock %}

View File

@@ -0,0 +1,8 @@
{% if "captcha" in form.fields %}
{% if form.captcha.errors %}
{% for error in form.captcha.errors %}
<p class="help-inline text-error">{{ error }}</p>
{% endfor %}
{% endif %}
{{ form.captcha }}
{% endif %}

View File

@@ -0,0 +1,292 @@
{% extends "zerver/base.html" %}
{% set entrypoint = "app" %}
{# The app itself. #}
{# Includes some other templates as tabs. #}
{% set PAGE_TITLE = _("Public view of {org_name} | Zulip team chat").format(org_name=realm_name) %}
{% set PAGE_DESCRIPTION = _("Browse the publicly accessible channels in {org_name} without logging in.").format(org_name=realm_name) %}
{% block meta_viewport %}
<!--
From version 132, Firefox now defaults to not resize the viewport
content but only the visual viewport. While this works well in
Chrome Android, it creates a buggy experience in Firefox Android
where the compose box is hidden under keyboard. To fix it, we rollback
to resizing content when keyboard is shown on Firefox Android.
TODO: Remove this when Firefox Android fixes the bug -
https://bugzilla.mozilla.org/show_bug.cgi?id=1943053 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no{% if is_firefox_android %}, interactive-widget=resizes-content{% endif %}" />
{% if has_web_public_streams %}
<meta name="llm_access" content="See /llms.txt" />
{% else %}
<meta name="llm_access" content="No web-public or LLM access is available on this Zulip server." />
{% endif %}
{% endblock %}
{% block customhead %}
{% if enable_gravatar %}<link rel="dns-prefetch" href="https://secure.gravatar.com" />
{% endif -%}
{% if s3_avatar_public_url_prefix %}<link rel="dns-prefetch" href="{{ s3_avatar_public_url_prefix }}" />
{% endif -%}
<meta name="mobile-web-app-capable" content="yes" />
<link href="{{ static('images/logo/apple-touch-icon-precomposed.png') }}" rel="apple-touch-icon-precomposed" />
<style>
#app-loading {
font-size: 16px;
background-color: hsl(0, 0%, 94%);
position: fixed;
height: 100%;
width: 100%;
padding: 10px;
top: 0px;
left: 0px;
z-index: 200;
}
#app-loading-middle-content, #app-loading-bottom-content {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: 10px;
}
#app-loading-middle-content h3 {
text-align: center;
}
@keyframes showAtEnd {
99% {
visibility: hidden;
}
100% {
visibility: visible;
}
}
#app-loading-unsupported-browser, #app-loading-unsupported-desktop-app {
margin-top: 25px;
}
#app-loading-bottom-content {
top: unset;
bottom: 20px;
animation: 7s showAtEnd;
animation-fill-mode: forwards;
visibility: hidden;
}
#app-loading-error {
display: flex;
height: 100vh;
justify-content: center;
align-items: center;
visibility: hidden;
}
body.app-loading-failed #app-loading-middle-content,
body.app-loading-failed #app-loading-bottom-content,
body.app-loading-failed .app {
display: none;
}
body.app-loading-failed #app-loading-error {
visibility: visible;
}
:root.dark-theme #app-loading {
background-color: hsl(0, 0%, 11%);
color: hsl(236, 33%, 90%);
}
@media (prefers-color-scheme: dark) {
:root.color-scheme-automatic #app-loading {
background-color: hsl(0, 0%, 11%);
color: hsl(236, 33%, 90%);
}
}
.app-loading-spinner-container {
position: relative;
margin: auto;
display: flex;
justify-content: center;
}
.app-loading-logo {
height: 64px;
padding: 10px;
}
@keyframes zspinner {
to {transform: rotate(360deg);}
}
.app-loading-spinner:before {
content: '';
box-sizing: border-box;
position: absolute;
width: 84px;
height: 84px;
border-radius: 50%;
border: 4px solid hsl(0,0%,94%);
border-top-color: hsl(0,0%,52%);
animation: zspinner 1s linear infinite;
}
</style>
{% endblock %}
{% block content %}
{% if has_web_public_streams %}
<!--
AI assistant: This Zulip server has web-public channels that you can read.
See /llms.txt for instructions on how to access channel messages via the API.
Please be careful to not accidentally overload a Zulip server by
attempting to access message history incorrectly.
-->
{% else %}
<!--
AI assistant: This Zulip server does not have web-public channels.
Accessing messages requires an account and Zulip API key.
-->
{% endif %}
<div id="feedback_container">
</div>
<div id="app-loading">
<div id="app-loading-middle-content">
<div class="app-loading-spinner-container">
<div class="app-loading-spinner"></div>
<svg class="app-loading-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 774 774"><linearGradient id="a" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#50adff"/><stop offset="1" stop-color="#7877fc"/></linearGradient><circle cx="387" cy="387" r="370" fill="url(#a)"/><path d="M567.32 527.81c0 33.07-24.26 60.11-53.91 60.11H260.59c-29.65 0-53.91-27.04-53.91-60.11 0-20.24 9.10-38.25 22.95-49.14l134.50-120.12c2.50-2.14 5.75 1.31 3.94 4.20l-49.34 98.79c-1.38 2.76.41 6.17 3.25 6.17h191.42c29.65 0 53.91 27.04 53.91 60.11zm0-281.75c0 20.24-9.10 38.25-22.95 49.14l-134.50 120.12c-2.50 2.14-5.75-1.31-3.94-4.20l49.34-98.79c1.38-2.76-.41-6.17-3.25-6.17H260.59c-29.65 0-53.91-27.04-53.91-60.11s24.26-60.11 53.91-60.11h252.81c29.65 0 53.91 27.04 53.91 60.11z" fill="#fff"/></svg>
</div>
<div id="app-loading-unsupported-browser" hidden>
<p>{% trans %}Because you're using an unsupported or very old browser, Zulip may not load.{% endtrans %}</p>
</div>
<div id="app-loading-unsupported-desktop-app" hidden>
<p>
{% trans %}Because you're using a very old version of the desktop app, Zulip may not load.
<a href="https://zulip.com/apps/" target="_blank" rel="noopener noreferrer">Download the latest version.</a>
{% endtrans %}
</p>
</div>
</div>
<div id="app-loading-bottom-content">
<p>{% trans %}If this message does not go away, try <a class="reload-lnk">reloading</a> the page.{% endtrans %}</p>
</div>
<div id="app-loading-error">
<p>{% trans %}Error loading Zulip. Try <a class="reload-lnk">reloading</a> the page.{% endtrans %}</p>
</div>
<script nonce="{{ csp_nonce }}">
document.addEventListener('DOMContentLoaded', function () {
function reload() {
window.location.reload(true);
}
document.querySelectorAll('.reload-lnk').forEach(lnk => lnk.addEventListener('click', reload));
});
</script>
</div>
<div id="tooltip-templates-container"></div>
<div id="channels_overlay_container"></div>
<div id="groups_overlay_container"></div>
<div id="drafts_table"></div>
<div id="scheduled_messages_overlay_container"></div>
<div id="reminders-overlay-container"></div>
<div id="settings_overlay_container" class="overlay" data-overlay="settings" aria-hidden="true">
</div>
<div id="message-edit-history-overlay-container"></div>
<div class="informational-overlays overlay" data-overlay="informationalOverlays" aria-hidden="true">
<div class="overlay-content overlay-container">
<div class="overlay-tabs">
<span class="exit">&times;</span>
</div>
<div class="overlay-body">
</div>
</div>
</div>
<div id="user-profile-modal-holder"></div>
<div id="about-zulip-modal-container"></div>
<div id="read-receipts-modal-container"></div>
<audio id="user-notification-sound-audio"></audio>
<audio id="realm-default-notification-sound-audio"></audio>
<div id="alert-popup-container">
<div id="popup_banners_wrapper" class="banner-wrapper alert-box">
<div class="alert alert_sidebar alert-error home-error-bar" id="home-error"></div>
</div>
</div>
<div class="blueslip-error-container"></div>
<div id="navbar-fixed-container">
<div id="navbar_alerts_wrapper" class="banner-wrapper"></div>
<div id="header-container"></div>
</div>
<div class="app">
<div class="app-main">
<div class="column-left" id="left-sidebar-container">
</div>
<div class="column-middle">
<div class="column-middle-inner">
<div id="recent_view" class="no-visible-focus-outlines">
<div class="recent_view_container">
<div id="recent_view_table"></div>
</div>
<table id="recent-view-content-table">
<tbody data-empty="{{ _('No conversations match your filters.') }}" id="recent-view-content-tbody"></tbody>
</table>
<div id="recent_view_bottom_whitespace">
<div class="bottom-messages-logo">
<svg class="messages-logo-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 774 774">
<circle cx="387" cy="387" r="370"/>
<path d="M567.32 527.81c0 33.07-24.26 60.11-53.91 60.11H260.59c-29.65 0-53.91-27.04-53.91-60.11 0-20.24 9.10-38.25 22.95-49.14l134.50-120.12c2.50-2.14 5.75 1.31 3.94 4.20l-49.34 98.79c-1.38 2.76.41 6.17 3.25 6.17h191.42c29.65 0 53.91 27.04 53.91 60.11zm0-281.75c0 20.24-9.10 38.25-22.95 49.14l-134.50 120.12c-2.50 2.14-5.75-1.31-3.94-4.20l49.34-98.79c1.38-2.76-.41-6.17-3.25-6.17H260.59c-29.65 0-53.91-27.04-53.91-60.11s24.26-60.11 53.91-60.11h252.81c29.65 0 53.91 27.04 53.91 60.11z"/>
</svg>
</div>
<div id="recent_view_loading_messages_indicator"></div>
</div>
<!-- Don't show the banner until we have some messages loaded. -->
<div class="recent-view-load-more-container main-view-banner info notvisible">
<div class="last-fetched-message banner_content">{{ _('This view is still loading messages.') }}</div>
<button class="fetch-messages-button main-view-banner-action-button right_edge notvisible">
<span class="loading-indicator"></span>
<span class="button-label">{{ _('Load more') }}</span>
</button>
</div>
</div>
<div id="inbox-view" class="no-visible-focus-outlines">
<div class="inbox-container">
<div id="inbox-pane"></div>
</div>
</div>
<div id="message_feed_container">
<div class="message-feed" id="main_div">
<div class="top-messages-logo">
<svg class="messages-logo-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 774 774">
<circle cx="387" cy="387" r="370"/>
<path d="M567.32 527.81c0 33.07-24.26 60.11-53.91 60.11H260.59c-29.65 0-53.91-27.04-53.91-60.11 0-20.24 9.10-38.25 22.95-49.14l134.50-120.12c2.50-2.14 5.75 1.31 3.94 4.20l-49.34 98.79c-1.38 2.76.41 6.17 3.25 6.17h191.42c29.65 0 53.91 27.04 53.91 60.11zm0-281.75c0 20.24-9.10 38.25-22.95 49.14l-134.50 120.12c-2.50 2.14-5.75-1.31-3.94-4.20l49.34-98.79c1.38-2.76-.41-6.17-3.25-6.17H260.59c-29.65 0-53.91-27.04-53.91-60.11s24.26-60.11 53.91-60.11h252.81c29.65 0 53.91 27.04 53.91 60.11z"/>
</svg>
</div>
<div id="loading_older_messages_indicator"></div>
<div id="page_loading_indicator"></div>
<div id="message_feed_errors_container"></div>
<div id="message-lists-container"></div>
<div id="scheduled_message_indicator">
</div>
<div id="mark_read_on_scroll_state_banner">
</div>
<div id="typing_notifications">
</div>
<div id="mark_read_on_scroll_state_banner_place_holder">
</div>
<div id="bottom_whitespace">
</div>
</div>
</div>
<div id="compose" {% if embedded %}data-embedded{% endif %}>
<div id="compose-container"></div>
</div>
</div>
</div>
<div class="column-right" id="right-sidebar-container">
</div><!--/right sidebar-->
</div>
</div>
<div class="hidden">
<form id="logout_form" action="/accounts/logout/" method="POST">{{ csrf_input }}
</form>
</div>
{% endblock %}

View File

@@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang='{{LANGUAGE_CODE}}' {% if color_scheme == 1 %} class="color-scheme-automatic" {% elif color_scheme == 2 %} class="dark-theme" {% endif %}>
{# Base template for the whole site. #}
<head>
<meta charset="UTF-8" />
{% block title %}
{% if user_profile and user_profile.realm.name %}
<title>{{user_profile.realm.name}} - Zulip</title>
{% else %}
{% if PAGE_TITLE %}
<title>{{ PAGE_TITLE }}</title>
{% endif %}
{% endif %}
{% endblock %}
<link id="favicon" rel="icon" href="{{ static('images/favicon.svg') }}?v=4" />
<link rel="alternate icon" href="{{ static('images/favicon.png') }}?v=4" />
{% block meta_viewport %}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{% endblock %}
{% if not user_profile %}
{% include 'zerver/meta_tags.html' %}
{% endif %}
{% if sentry_params is defined %}
<script id="sentry-params" type="text/json">{{ sentry_params|tojson }}</script>
{% endif %}
{% block webpack %}
{% for filename in webpack_entry(entrypoint) -%}
{% if filename.endswith(".css") -%}
<link href="{{ filename }}" rel="stylesheet" {% if csp_nonce %}nonce="{{ csp_nonce }}"{% endif %} />
{% elif filename.endswith(".js") -%}
<script src="{{ filename }}" defer crossorigin="anonymous" {% if csp_nonce %}nonce="{{ csp_nonce }}"{% endif %}></script>
{% endif -%}
{% endfor %}
{% endblock %}
{% block customhead %}
{% endblock %}
</head>
<body>
{% block content %}
{% endblock %}
{% set all_page_params = default_page_params.copy() %}
{% set _ = all_page_params.update(page_params|default({})) %}
<div hidden id="page-params" data-params='{{ all_page_params|tojson }}'></div>
</body>
</html>
{% set entrypoint = entrypoint|default("common") %}

View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>{{ _("Video call ended") }} | Zulip</title>
<script>
window.close();
// Why doesn’t this work in Firefox? See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1353466
</script>
</head>
<body>
<p>{{ _("You may now close this window.") }}</p>
</body>
</html>

View File

@@ -0,0 +1,33 @@
{% extends "zerver/config_error/social-container.html" %}
{% block error_content %}
<p>
You are attempting to use the <strong>Apple auth backend</strong>, but it is
not properly configured. To configure, please check the following:
</p>
<ul>
<li>
You have registered
<code>{{ root_domain_url }}/complete/apple/</code> as the callback URL
for your Services ID in Apple’s developer console. You can enable “Sign
in with Apple” for an app at
<a href="https://developer.apple.com/account/resources/">Certificates,
Identifiers &amp; Profiles</a>.
</li>
<li>
You have set <code>SOCIAL_AUTH_APPLE_SERVICES_ID</code>,
<code>SOCIAL_AUTH_APPLE_APP_ID</code>,
<code>SOCIAL_AUTH_APPLE_TEAM</code>, and
<code>SOCIAL_AUTH_APPLE_KEY</code> in
<code>{{ auth_settings_path }}</code>
and stored the private key provided by Apple at
<code>/etc/zulip/apple-auth-key.p8</code> on the Zulip server, with
proper permissions set.
</li>
<li>
Navigate back to the login page and attempt the “Sign in with Apple”
flow again.
</li>
</ul>
{{ super() }}
{% endblock %}

View File

@@ -0,0 +1,34 @@
{% extends "zerver/portico.html" %}
{% block title %}
<title>{{ _("Configuration error") }} | Zulip</title>
{% endblock %}
{% block portico_content %}
<div id="config_error_page" class="flex full-page">
<div class="new-style">
<div class="pitch">
<h1>
{{ _("Configuration error") }}
</h1>
</div>
<div class="white-box">
<div class="errorbox config-error">
<div class="errorcontent">
{% block error_body %}
<p>
{% block error_content %}
{% endblock %}
</p>
<p>After making your changes, remember to restart the Zulip server.</p>
<p><a href="">Refresh</a> to try again or
<a href="{{ go_back_to_url }}">go back to {{ go_back_to_url_name }}</a>.</p>
{% endblock %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,23 @@
{% extends "zerver/config_error/container.html" %}
{% block error_content %}
<p>
You attempted to use the <code>DevAuthBackend</code> authentication method,
which is used for logging in without a password in the Zulip development
environment.
</p>
<p>This backend is not available for this realm, either because:</p>
<ul>
<li>This Zulip server is configured as a production server.</li>
<li>
<code>DevAuthBackend</code> is disabled in
<code>AUTHENTICATION_BACKENDS</code> in
<code>{{ auth_settings_path }}</code>.
</li>
<li>
You disabled this authentication backend in
<a href="/help/configure-authentication-methods">this realm’s
authentication settings</a>.
</li>
</ul>
{% endblock %}

View File

@@ -0,0 +1,28 @@
{% extends "zerver/config_error/social-container.html" %}
{% block error_content %}
<p>
You are attempting to use the <strong>Discord auth backend</strong>, but it
is not properly configured. To configure, please check the following:
</p>
<ul>
<li>
You have added
<code>{{ root_domain_url }}/complete/discord/</code> as the callback URL
in the OAuth application in Discord Developer Portal. You can register
OAuth apps at <a href="https://discord.com/developers/applications">Discord
Developer Portal</a>.
</li>
<li>
You have set <code>{{ client_id_key_name }}</code> in
<code>{{ auth_settings_path }}</code> and
<code>social_auth_discord_secret</code> in
<code>{{ secrets_path }}</code> with the values from your OAuth
application.
</li>
<li>
Navigate back to the login page and attempt the Discord auth flow again.
</li>
</ul>
{{ super() }}
{% endblock %}

View File

@@ -0,0 +1,28 @@
{% extends "zerver/config_error/social-container.html" %}
{% block error_content %}
<p>
You are attempting to use the <strong>GitHub auth backend</strong>, but it
is not properly configured. To configure, please check the following:
</p>
<ul>
<li>
You have added
<code>{{ root_domain_url }}/complete/github/</code> as the callback URL
in the OAuth application in GitHub. You can create OAuth apps from
<a href="https://github.com/settings/developers">GitHub’s developer
site</a>.
</li>
<li>
You have set <code>{{ client_id_key_name }}</code> in
<code>{{ auth_settings_path }}</code> and
<code>social_auth_github_secret</code> in
<code>{{ secrets_path }}</code> with the values from your OAuth
application.
</li>
<li>
Navigate back to the login page and attempt the GitHub auth flow again.
</li>
</ul>
{{ super() }}
{% endblock %}

View File

@@ -0,0 +1,28 @@
{% extends "zerver/config_error/social-container.html" %}
{% block error_content %}
<p>
You are attempting to use the <strong>GitLab auth backend</strong>, but it
is not properly configured. To configure, please check the following:
</p>
<ul>
<li>
You have added
<code>{{ root_domain_url }}/complete/gitlab/</code> as the callback URL
in the OAuth application in GitLab. You can register OAuth apps at
<a href="https://gitlab.com/profile/applications">GitLab
applications</a>.
</li>
<li>
You have set <code>{{ client_id_key_name }}</code> in
<code>{{ auth_settings_path }}</code> and
<code>social_auth_gitlab_secret</code> in
<code>{{ secrets_path }}</code> with the values from your OAuth
application.
</li>
<li>
Navigate back to the login page and attempt the GitLab auth flow again.
</li>
</ul>
{{ super() }}
{% endblock %}

View File

@@ -0,0 +1,31 @@
{% extends "zerver/config_error/social-container.html" %}
{% block error_content %}
<p>
You are attempting to use the <strong>Google auth backend</strong>, but it
is not properly configured. To configure, please check the following:
</p>
<ul>
<li>
You have created a Google OAuth2 client and enabled the Identity Toolkit
API. You can create OAuth2 apps at
<a href="https://console.developers.google.com">the Google developer
console</a>.
</li>
<li>
You have configured your OAuth2 client to allow redirects to your
server’s Google auth URL:
<code>{{ root_domain_url }}/complete/google/</code>.
</li>
<li>
You have set <code>{{ client_id_key_name }}</code> in
<code>{{ auth_settings_path }}</code> and
<code>social_auth_google_secret</code> in
<code>{{ secrets_path }}</code>.
</li>
<li>
Navigate back to the login page and attempt the Google auth flow again.
</li>
</ul>
{{ super() }}
{% endblock %}

View File

@@ -0,0 +1,9 @@
{% extends "zerver/config_error/container.html" %}
{% block error_content %}
{% trans %}
You are trying to log in using LDAP without creating an
organization first. Please use EmailAuthBackend to create
your organization and then try again.
{% endtrans %}
{% endblock %}

View File

@@ -0,0 +1,8 @@
{% extends "zerver/config_error/container.html" %}
{% block error_content %}
{# TODO: Improve the config error page for OIDC #}
<p>
The OpenID Connect backend is not configured correctly.
</p>
{% endblock %}

View File

@@ -0,0 +1,92 @@
{% extends "zerver/config_error/container.html" %}
{% macro setting() -%}
{%- if helm_config -%}
<code>zulip.environment.LOADBALANCER_IPS</code> in your Helm values
{%- elif docker_config -%}
<code>LOADBALANCER_IPS</code> in your Docker image's environment
{%- else -%}
<code>ips</code> in the <code>[loadbalancer]</code> section of <code>/etc/zulip/zulip.conf</code>
{%- endif -%}
{%- endmacro %}
{% block error_body %}
{% if not current_proxies and not x_forwarded_for %}
<p>
You have not configured any reverse proxies in {{ setting() }},
and an HTTP request was received without any reverse proxy
headers. Zulip requires that all client traffic to it be over
HTTPS. Since you have configured Zulip itself to be served over
HTTP, it must be placed behind a proxy which does TLS termination.
</p>
<p>
You must configure a reverse proxy in front of Zulip which serves
traffic over HTTPS, and configure Zulip to trust that proxy, by
adding its IP to {{ setting() }}. See our <a href="https://zulip.readthedocs.io/en/stable/production/reverse-proxies.html"
>documentation about deploying behind reverse proxies</a> for more
details.
</p>
{% elif not current_proxies %}
<p>
You have not configured any reverse proxies in {{ setting() }},
but reverse proxy headers were detected in a request from
<code>{{ remote_addr }}</code>.
</p>
<p>
Add <code>{{ remote_addr }}</code> to {{ setting() }} and restart
your Zulip server. See
our <a href="https://zulip.readthedocs.io/en/stable/production/reverse-proxies.html"
>documentation about deploying behind reverse proxies</a> for more
details.
</p>
{% elif not x_forwarded_proto %}
<p>
You have configured reverse proxies (<code>{{ current_proxies }}</code>),
and traffic is being served through them, but the remote proxy did
not send an <code>X-Forwarded-Proto</code> header.
</p>
<p>
Please read our <a href="https://zulip.readthedocs.io/en/stable/production/reverse-proxies.html"
>documentation about configuring your reverse proxy</a>, and
configure your proxy to send an <code>X-Forwarded-Proto</code>
header.
</p>
{% else %}
<p>
You have configured reverse proxies (<code>{{ current_proxies }}</code>),
but this request did not come from a matching IP address -- it
came from <code>{{ remote_addr }}</code>.
</p>
<p>
You should update {{ setting() }} to include <code>{{ remote_addr }}</code>,
and restart your Zulip server. See our <a href="https://zulip.readthedocs.io/en/stable/production/reverse-proxies.html"
>documentation about deploying behind reverse proxies</a> for more
details.
</p>
{% endif %}
<hr />
<h2>Request headers:</h2>
<pre>
{% for item in all_headers -%}
{% if item[1] != "" -%}
{{ item[0] }}: {{ item[1] }}
{% endif -%}
{% endfor -%}
</pre>
{% endblock %}

View File

@@ -0,0 +1,9 @@
{% extends "zerver/config_error/container.html" %}
{% block error_content %}
{% trans doc_url="https://zulip.readthedocs.io/en/latest/production/mobile-push-notifications.html" %}
This server is not configured to use push notifications. For instructions on how to
configure push notifications, please see the
<a href="{{ doc_url }}">documentation</a>.
{% endtrans %}
{% endblock %}

View File

@@ -0,0 +1,8 @@
{% extends "zerver/config_error/container.html" %}
{% block error_content %}
<p>
Authentication via the REMOTE_USER header is
disabled in `/etc/zulip/settings.py`.
</p>
{% endblock %}

View File

@@ -0,0 +1,7 @@
{% extends "zerver/config_error/container.html" %}
{% block error_content %}
<p>
The REMOTE_USER header is not set.
</p>
{% endblock %}

View File

@@ -0,0 +1,15 @@
{% extends "zerver/config_error/container.html" %}
{% block error_content %}
<p>
SAML authentication is either not enabled or misconfigured. Have a look at
our <a href="https://zulip.readthedocs.io/en/latest/production/authentication-methods.html#SAML">setup guide</a>.
</p>
{% if development_environment %}
<p>
See also the
<a href="https://zulip.readthedocs.io/en/latest/development/authentication.html#saml">SAML guide</a>
for the development environment.
</p>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,26 @@
{% extends "zerver/config_error/container.html" %}
{% block error_content %}
<p>
It appears there are problems with the
email configuration.
</p>
{% if not development_environment %}
<p>
See <code>/var/log/zulip/errors.log</code> for more
details on the error.
</p>
<p>
You may also want to test your email configuration,
as described in the
<a href="https://zulip.readthedocs.io/en/latest/production/email.html">Production installation docs</a>.
</p>
{% else %}
<p>
Please have a look at our
<a target="_blank" rel="noopener noreferrer" href="https://zulip.readthedocs.io/en/latest/subsystems/email.html#development-and-testing"> setup guide</a>
for forwarding emails sent in development
environment to an email account.
</p>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,17 @@
{% extends "zerver/config_error/container.html" %}
{% block error_content %}
{% if development %}
<p>
For more information, have a look at the
<a href="https://zulip.readthedocs.io/en/latest/development/authentication.html#{{ social_backend_name }}">authentication setup guide</a>
for the development environment.
</p>
{% else %}
<p>
For more information, have a look at our
<a href="https://zulip.readthedocs.io/en/latest/production/authentication-methods.html">authentication setup guide</a>
and the comments in <code>{{ settings_comments_path }}</code>.
</p>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,52 @@
{% extends "zerver/portico_signup.html" %}
{% block title %}
<title>{{ _("Account not found") }} | Zulip</title>
{% endblock %}
{% block portico_content %}
<div class="app register-page">
<div class="app-main confirm-continue-page-container">
<div class="center-container">
<div class="center-block">
<div class="register-form new-style">
<div class="lead">
<h1 class="get-started">{{ _("Zulip account not found.") }}</h1>
</div>
<div class="white-box">
<p>
{% trans %}
No account found for {{ email }}.
{% endtrans %}
</p>
<div style="text-align: center;">
<form class="form-inline" id="send_confirm" name="send_confirm"
action="/login/" method="get">
<input type="hidden"
id="email"
name="email"
value="{{ email }}" />
<button>
{{ _("Log in with another account") }}
</button>
</form>
<br />
<form class="form-inline" id="send_confirm" name="send_confirm"
action="{{ continue_link }}" method="get">
<button class="outline">
{{ _("Continue to registration") }}
</button>
{% if full_name %}
<input type="hidden" name="full_name" value="{{ full_name }}" />
{% endif %}
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="footer-padder"></div>
</div>
{% endblock %}

View File

@@ -0,0 +1,33 @@
{% extends "zerver/portico_signup.html" %}
{% block title %}
<title>{{ _("Try Zulip in a demo organization") }} | Zulip</title>
{% endblock %}
{% block portico_content %}
<div class="register-account flex full-page">
<div class="center-block new-style" id="demo-realm-creation">
<div class="registration-lead-section">
<h1 class="registration-lead-title">{{ _("Try Zulip in a demo organization") }}</h1>
<p class="registration-lead-subtitle">
{% trans %}
No email required. Or <a class="registration-lead-subtitle-link" href="{{ root_domain_url }}/new/">create a permanent organization</a>.
{% endtrans %}
</p>
</div>
<form class="white-box" id="create_demo_realm" action="{{ current_url() }}" method="post">
{{ csrf_input }}
<input type='hidden' name='timezone' id='demo-creator-timezone'/>
{% include 'zerver/create_realm/realm_creation_base_form_fields.html' %}
{% include 'zerver/create_realm/found_zulip_form_field.html' %}
{% if terms_of_service %}
{% include 'zerver/create_user/terms_of_service_form_field.html' %}
{% endif %}
<div class="input-box" id="demo-submit-button-container">
<button type="submit" class="new-organization-button register-button">{{ _("Try Zulip") }}</button>
{% include 'zerver/altcha_form_field.html' %}
</div>
</form>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,67 @@
{% extends "zerver/portico_signup.html" %}
{# Home page for not logged-in users. #}
{% block title %}
<title>{{ _("Create a new organization") }} | Zulip</title>
{% endblock %}
{# This is where we pitch the app and solicit signups. #}
{% block portico_content %}
<div class="app register-page">
<div class="app-main register-page-container new-style flex full-page">
<div class="register-form" id="new-realm-creation">
<div class="registration-lead-section">
<h1 class="registration-lead-title">{{ _("Create a new Zulip organization") }}</h1>
{% if corporate_enabled %}
<p class="registration-lead-subtitle">
{% trans %}
Or <a class="registration-lead-subtitle-link" href="{{ root_domain_url }}/new/demo/">create a demo organization</a> — no email required!
{% endtrans %}
</p>
{% endif %}
</div>
<div class="white-box">
<form class="form-inline" id="create_realm" name="email_form"
action="{{ current_url() }}" method="post">
{{ csrf_input }}
{% include 'zerver/create_realm/realm_creation_name_form_field.html' %}
{% include 'zerver/create_realm/realm_creation_base_form_fields.html' %}
{% include 'zerver/create_realm/realm_creation_subdomain_form_field.html' %}
{% if is_realm_import_enabled %}
{% include 'zerver/create_realm/realm_creation_import_form_field.html' %}
{% endif %}
<div class="input-box horizontal">
<div class="inline-block relative">
<input type="text" class="email required" placeholder="{{ _("Enter your email address") }}"
id="email" name="email" required />
<label for="email">{{ _('Your email') }}</label>
</div>
{% if form.email.errors %}
{% for error in form.email.errors %}
<div class="alert alert-error">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
<div class="input-box" id="altcha-submit-button-container">
<button type="submit" class="new-organization-button register-button">{{ _("Create organization") }}</button>
{% include 'zerver/altcha_form_field.html' %}
</div>
</form>
</div>
{% if not is_realm_import_enabled %}
<div class="bottom-text">
{% trans %}
Or import
from <a href="/help/import-from-slack">Slack</a>, <a href="/help/import-from-mattermost">Mattermost</a>,
or <a href="/help/import-from-rocketchat">Rocket.Chat</a>.
{% endtrans %}
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,24 @@
<div class="input-group input-box" id="how-realm-creator-found-zulip">
<label for="how_realm_creator_found_zulip">
{{ _('How did you first hear about Zulip?') }}
{% if not corporate_enabled %}
<i class="fa fa-question-circle-o" aria-hidden="true" data-tippy-content="{% trans %}This value is used only if you sign up for a plan, in which case it will be sent to the Zulip team.{% endtrans %}"></i>
{% endif %}
</label>
<select id="how_realm_creator_found_zulip" name="how_realm_creator_found_zulip" class="required" required>
<option value="" selected disabled>{{ _('Select an option') }}</option>
{% for option_id, option_name in how_realm_creator_found_zulip_options %}
<option value="{{ option_id }}">{{ option_name }}</option>
{% endfor %}
</select>
<input id="how-realm-creator-found-zulip-other" class="how-found-zulip-extra-data-input" type="text" placeholder="{{ _('Please describe') }}" name="how_realm_creator_found_zulip_other_text" maxlength="100"/>
<input id="how-realm-creator-found-zulip-where-ad" class="how-found-zulip-extra-data-input" type="text" placeholder="{{ _('Where did you see the ad?') }}" name="how_realm_creator_found_zulip_where_ad" maxlength="100"/>
<input id="how-realm-creator-found-zulip-which-organization" class="how-found-zulip-extra-data-input" type="text" placeholder="{{ _('Which organization?') }}" name="how_realm_creator_found_zulip_which_organization" maxlength="100"/>
<input id="how-realm-creator-found-zulip-review-site" class="how-found-zulip-extra-data-input" type="text" placeholder="{{ _('Which one?') }}" name="how_realm_creator_found_zulip_review_site" maxlength="100"/>
<input id="how-realm-creator-found-zulip-which-ai-chatbot" class="how-found-zulip-extra-data-input" type="text" placeholder="{{ _('Which one?') }}" name="how_realm_creator_found_zulip_which_ai_chatbot" maxlength="100"/>
{% if form.how_realm_creator_found_zulip.errors %}
{% for error in form.how_realm_creator_found_zulip.errors %}
<p class="error help-inline alert alert-error">{{ error }}</p>
{% endfor %}
{% endif %}
</div>

View File

@@ -0,0 +1,37 @@
<div class="realm-creation-editable-inputs {% if user_registration_form and not form.realm_subdomain.errors %}hide{% endif %}">
<div class="input-box">
<div class="inline-block relative">
<select name="realm_type" id="realm_type" required>
<option disabled selected value>-- {{ _("Select one") }} --</option>
{% for realm_type in sorted_realm_types %}
{% if not realm_type.hidden %}
<option value="{{ realm_type.id }}" {% if form.realm_type.value() == realm_type.id %}selected{% endif %} >{{ _(realm_type.name) }}</option>
{% endif %}
{% endfor %}
</select>
</div>
<label for="realm_type" class="inline-block label-title">{{ _('Organization type') }}
<a href="/help/organization-type" target="_blank" rel="noopener noreferrer">
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
</a>
</label>
</div>
<div class="input-box">
<div class="inline-block relative">
<select name="realm_default_language" id="realm_default_language">
{% for language in language_list %}
<option value="{{ language.code }}" {% if form.realm_default_language.value() == language.code %}selected{% endif %} >{{ _(language.name) }}</option>
{% endfor %}
</select>
</div>
<label for="realm_default_language" class="inline-block label-title">
{{ _('Organization language') }}
<a href="/help/configure-organization-language" target="_blank" rel="noopener noreferrer">
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
</a>
</label>
</div>
</div>

View File

@@ -0,0 +1,27 @@
<div class="realm-creation-editable-inputs {% if user_registration_form and not form.realm_subdomain.errors %}hide{% endif %}">
<div class="input-box">
<div class="inline-block" id="realm-creation-import-from-wrapper">
<select id="import_from" name="import_from"
{% if user_registration_form %}
disabled
{% endif %}
>
{% for key, choice in import_from_choices %}
<option value="{{ key }}" {% if key == "none" %}selected{% endif %}>{{ _(choice) }}</option>
{% endfor %}
</select>
{% if not user_registration_form %}
<p class="extra-info-realm-creation-import-from registration-form-hint">
{% trans %}
Learn how to import from
<a href="/help/import-from-mattermost">Mattermost</a> or
<a href="/help/import-from-rocketchat">Rocket.Chat</a>.
{% endtrans %}
</p>
{% endif %}
</div>
<label for="import_from" class="inline-block">
{{ _('Import chat history?') }}
</label>
</div>
</div>

View File

@@ -0,0 +1,20 @@
<div class="realm-creation-editable-inputs {% if user_registration_form and not form.realm_subdomain.errors %}hide{% endif %}">
<div class="input-box">
<div class="inline-block relative">
<input id="id_team_name" class="required" type="text"
value="{% if form.realm_name.value() %}{{ form.realm_name.value() }}{% endif %}"
name="realm_name" maxlength="{{ MAX_REALM_NAME_LENGTH }}" required {% if not user_registration_form %}autofocus{% endif %} />
</div>
<label for="id_team_name" class="inline-block label-title">
{{ _('Organization name') }}
<a href="/help/create-your-organization-profile" target="_blank" rel="noopener noreferrer">
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
</a>
</label>
{% if form.realm_name.errors %}
{% for error in form.realm_name.errors %}
<p class="help-inline text-error">{{ error }}</p>
{% endfor %}
{% endif %}
</div>
</div>

View File

@@ -0,0 +1,35 @@
<div class="realm-creation-editable-inputs {% if user_registration_form and not form.realm_subdomain.errors %}hide{% endif %}">
<div class="input-box">
<label class="static org-url">
{{ _('Organization URL') }}
</label>
{% if root_domain_available %}
<label class="checkbox static" for="realm_in_root_domain">
<input type="checkbox" name="realm_in_root_domain" id="realm_in_root_domain"
{% if not form.realm_subdomain.value() and not form.realm_subdomain.errors %}checked="checked"{% endif %}/>
<span class="rendered-checkbox"></span>
{% trans %}Use {{ external_host }}{% endtrans %}
</label>
{% endif %}
<div id="subdomain_section" {% if root_domain_available and
not form.realm_subdomain.errors and not form.realm_subdomain.value() %}style="display: none;"{% endif %}>
<div class="or"><span>{{ _('OR') }}</span></div>
<div class="inline-block relative">
<input id="id_team_subdomain"
class="{% if root_domain_landing_page %}required{% endif %} subdomain" type="text"
placeholder="acme"
value="{% if form.realm_subdomain.value() %}{{ form.realm_subdomain.value() }}{% endif %}"
name="realm_subdomain" maxlength="{{ MAX_REALM_SUBDOMAIN_LENGTH }}"
{% if root_domain_landing_page %}required{% endif %} />
<label for="id_team_subdomain" class="realm_subdomain_label">.{{ external_host }}</label>
<p id="id_team_subdomain_error_client" class="error help-inline text-error"></p>
</div>
{% if form.realm_subdomain.errors %}
{% for error in form.realm_subdomain.errors %}
<p class="error help-inline text-error team_subdomain_error_server">{{ error }}</p>
{% endfor %}
{% endif %}
</div>
</div>
</div>

View File

@@ -0,0 +1,104 @@
{% extends "zerver/portico_signup.html" %}
{# Home page for not logged-in users. #}
{% block title %}
<title>{{ _("Sign up") }} | Zulip</title>
{% endblock %}
{# This is where we pitch the app and solicit signups. #}
{% block portico_content %}
<!-- The following empty tag has unique data-page-id so that this
page can be easily identified in it's respective JavaScript file -->
<div data-page-id="accounts-home"></div>
<div class="app register-page split-view flex full-page new-style">
<div class="inline-block">
<div class="lead">
<h1 class="get-started">{{ _("Sign up for Zulip") }}</h1>
</div>
<div class="app-main register-page-container white-box {% if realm_invite_required and not from_multiuse_invite %}closed-realm{% endif %}">
<div class="register-form new-style">
{% if realm_name %}
<div class="left-side">
<div class="org-header">
<img class="avatar" src="{{ realm_icon }}" alt="" />
<div class="info-box">
<div class="organization-name">{{ realm_name }}</div>
<div class="organization-path">{{ realm_url }}</div>
</div>
</div>
<div class="description">
{{ realm_description|safe }}
</div>
<div class="invite-required">
<hr />
<i class="fa fa-lock"></i>{{ _("You need an invitation to join this organization.") }}
</div>
</div>
{% endif %}
<div class="right-side">
{% if no_auth_enabled %}
<div class="alert">
<p>No authentication backends are enabled on this
server yet, so it is impossible to register!</p>
<p>
See
the <a href="https://zulip.readthedocs.io/en/latest/production/install.html#step-3-configure-zulip">Zulip
authentication documentation</a> to learn how to
configure authentication backends.
</p>
</div>
{% else %}
{% if password_auth_enabled %}
<form class="form-inline" id="send_confirm" name="email_form"
action="{{ current_url() }}" method="post">
{{ csrf_input }}
<div class="input-box no-validate">
<input type="email" id="email" class="email" name="email" value="" autofocus required />
<label for="email">{{ _('Email') }}</label>
<div class="alert alert-error email-frontend-error"></div>
{% if form.email.errors %}
{% for error in form.email.errors %}
<div class="email-backend-error alert alert-error">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
<button class="full-width" type="submit">{{ _('Sign up') }}</button>
</form>
{% if external_authentication_methods|length > 0 %}
<div class="or"><span>{{ _('OR') }}</span></div>
{% endif %}
{% endif %}
{% for backend in external_authentication_methods %}
<div class="login-social">
<form class="form-inline" action="{{ backend.signup_url }}" method="get">
{% if next %}
<input type="hidden" name="next" value="{{ next }}" />
{% endif %}
<input type='hidden' name='multiuse_object_key' value='{{ multiuse_object_key }}' />
<button id="register_auth_button_{{ backend.name }}" class="login-social-button full-width"
{% if backend.display_icon %} style="background-image:url({{ backend.display_icon }})" {% endif %}>
{{ _('Sign up with %(identity_provider)s', identity_provider=backend.display_name) }}
</button>
</form>
</div>
{% endfor %}
<div class="register-form-login-redirect actions">
{{ _('Already have an account?') }}<a class="register-link" href="/login/"> {{ _('Log in') }}</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,37 @@
<div class="micromodal" id="change-email-address-visibility-modal" aria-hidden="true">
<div class="modal__overlay" tabindex="-1">
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="change-email-address-visibility-modal-label">
<header class="modal__header">
<div class="modal__header-content">
<h1 id="change-email-address-visibility-modal-label" class="modal__title dialog_heading">
{{ _('Configure email address privacy') }}
</h1>
</div>
<button type="button" class="modal__close" aria-label="{{ _('Close modal') }}" tabindex="0" data-micromodal-close>
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
</header>
<main class="modal__content">
<p>
{{ _('Zulip lets you control which roles in the organization can view your email address.') }}
{{ _('Do you want to change the privacy setting for your email from the default configuration for this organization?') }}
</p>
<label for="new_user_email_address_visibility">{{ _('Who can access your email address') }}</label>
<select id="new_user_email_address_visibility" class="modal_select">
{% for value, name in email_address_visibility_options_dict.items() %}
<option value="{{ value }}" {% if value == default_email_address_visibility %}selected{% endif %}>{{name}}</option>
{% endfor %}
</select>
<p>
{% trans %}You can also change this setting <a href="{{ root_domain_url }}/help/configure-email-visibility" target="_blank" rel="noopener noreferrer">after you join</a>.{% endtrans %}
</p>
</main>
<footer class="modal__footer">
<button class="modal__button dialog_exit_button" aria-label="{{ '(Close this dialog window)' }}" data-micromodal-close>{{ _('Cancel') }}</button>
<button class="modal__button dialog_submit_button">
<span>{{ _('Confirm') }}</span>
</button>
</footer>
</div>
</div>
</div>

View File

@@ -0,0 +1,19 @@
<p id="new-user-email-address-visibility" class="registration-form-hint">
<input type="hidden" name="email_address_visibility" value="{{ default_email_address_visibility }}" id="email_address_visibility"/>
<span class="current-selected-option">
{% if default_email_address_visibility == email_address_visibility_admins_only %}
{% trans %}Administrators of this Zulip organization will be able to see this email address.
{% endtrans %}
{% elif default_email_address_visibility == email_address_visibility_moderators %}
{% trans %}Administrators and moderators of this Zulip organization will be able to see this email address.
{% endtrans %}
{% elif default_email_address_visibility == email_address_visibility_nobody %}
{% trans %}Nobody in this Zulip organization will be able to see this email address.
{% endtrans %}
{% else %}
{% trans %}Other users in this Zulip organization will be able to see this email address.
{% endtrans %}
{% endif %}
</span>
<a target="_blank" class="change_email_address_visibility" rel="noopener noreferrer">{{ _('Change') }}</a>
</p>

View File

@@ -0,0 +1,239 @@
{% extends "zerver/portico_signup.html" %}
{% set entrypoint = "register" %}
{% block title %}
<title>{{ _("Registration") }} | Zulip</title>
{% endblock %}
{#
Gather other user information, after having confirmed
their email address.
Form is validated both client-side using jquery-validation (see signup.js) and server-side.
#}
{% block portico_content %}
<div class="register-account flex full-page">
<div class="center-block new-style" id="create-account">
<div class="pitch">
{% if creating_new_realm %}
<h1>{{ _('Create your organization') }}</h1>
{% else %}
<h1>{{ _('Create your account') }}</h1>
{% endif %}
{% trans %}
<p>Enter your account details to complete registration.</p>
{% endtrans %}
</div>
<form method="post" class="white-box" id="registration" action="{{ url('accounts_register') }}">
{{ csrf_input }}
<fieldset class="org-registration">
{% if creating_new_realm %}
<legend>{{ _('Your organization') }}
{% if not form.realm_subdomain.errors %}
<span class="edit-realm-details" role="button" tabindex="0"><i class="fa fa-pencil"></i></span>
{% endif %}
</legend>
{% with %}
{% set user_registration_form = "true" %}
{% include 'zerver/create_realm/realm_creation_name_form_field.html' %}
{% include 'zerver/create_realm/realm_creation_base_form_fields.html' %}
{% include 'zerver/create_realm/realm_creation_subdomain_form_field.html' %}
{% if is_realm_import_enabled %}
{% include 'zerver/create_realm/realm_creation_import_form_field.html' %}
{% endif %}
{% endwith %}
{% if not form.realm_subdomain.errors %}
<div class="not-editable-realm-details">
<div class="input-box">
<label for="id_realm_name" class="inline-block label-title">{{ _('Organization name') }}</label>
<div id="id_realm_name" class="not-editable-realm-field">{{ form.realm_name.value() }}</div>
</div>
<div class="input-box">
<label for="id_realm_type" class="inline-block label-title">{{ _('Organization type') }}</label>
<div id="id_realm_type" class="not-editable-realm-field">{{ selected_realm_type_name }}</div>
</div>
<div class="input-box">
<label for="id_realm_default_language" class="inline-block label-title">{{ _('Organization language') }}</label>
<div id="id_realm_default_language" class="not-editable-realm-field">{{ selected_realm_default_language_name }}</div>
</div>
<div class="input-box">
<label for="id_realm_subdomain" class="inline-block label-title">{{ _('Organization URL') }}</label>
<div id="id_realm_subdomain" class="not-editable-realm-field">{% if form.realm_subdomain.value() %}{{ form.realm_subdomain.value() }}.{% endif %}{{external_host}}</div>
</div>
</div>
{% endif %}
{% endif %}
</fieldset>
<fieldset class="user-registration">
{% if creating_new_realm %}
<legend>{{ _('Your account') }}</legend>
{% endif %}
{% if realm_name and not creating_new_realm %}
<img class="avatar inline-block" src="{{ realm_icon }}" alt="" />
<div class="info-box inline-block">
<div class="organization-name organization-name-delayed-tooltip">{{ realm_name }}</div>
<div class="organization-path">{{ realm_url }}</div>
</div>
{% endif %}
<div class="input-box">
<input type='hidden' name='key' value='{{ key }}' />
<input type='hidden' name='timezone' id='timezone'/>
<label for="id_email" class="inline-block label-title">{{ _('Email') }}</label>
<div id="id_email">{{ email }}</div>
{% if not creating_new_realm %}
{% include 'zerver/create_user/new_user_email_address_visibility.html' %}
{% endif %}
</div>
{% if accounts %}
<div class="input-box">
<div class="inline-block relative">
<select class="select" name="source_realm_id" id="source_realm_select">
<option value=""
{% if "source_realm_id" in form.data and form.data["source_realm_id"] == "" %}selected {% endif %}>
{{ _('Don&rsquo;t import settings') }}
</option>
{% for account in accounts %}
<option value="{{ account.realm_id }}" data-full-name="{{account.full_name}}" data-avatar="{{account.avatar}}"
{% if ("source_realm_id" in form.data and account.realm_id == form.data["source_realm_id"]|int)
or ("source_realm_id" not in form.data and loop.index0 == 0) %} selected {% endif %}>
{{ account.realm_name }}
</option>
{% endfor %}
</select>
</div>
<label for="source_realm_id" class="inline-block">{{ _('Import settings from existing Zulip account') }}
<a href="{{ root_domain_url }}/help/import-your-settings"><i class="fa fa-question-circle"></i></a>
</label>
</div>
{% endif %}
<div class="input-box" id="full_name_input_section">
{% if lock_name %}
<p class="fakecontrol">{{ full_name }}</p>
{% else %}
<input id="id_full_name" class="required" type="text" name="full_name"
value="{% if full_name %}{{ full_name }}{% elif form.full_name.value() %}{{ form.full_name.value() }}{% endif %}"
maxlength="{{ MAX_NAME_LENGTH }}" placeholder="{% trans %}Your full name{% endtrans %}" required />
<label for="id_full_name" class="inline-block label-title">{{ _('Name') }}</label>
{% if form.full_name.errors %}
{% for error in form.full_name.errors %}
<p class="help-inline text-error">{{ error }}</p>
{% endfor %}
{% endif %}
{% endif %}
<p class="registration-form-hint">{{ _('This is how your account is displayed in Zulip.') }}</p>
</div>
<div class="input-box" id="profile_info_section" style="display:none;">
<img id="profile_avatar" />
<div id="profile_full_name"></div>
</div>
{% if require_ldap_password %}
<div class="input-box password-div">
<input id="ldap-password" class="required" type="password" name="password" autocomplete="off" required />
<label for="ldap-password" class="inline-block">{{ _('Password') }}</label>
<i class="zulip-icon zulip-icon-hide password_visibility_toggle" role="button" tabindex="0"></i>
<span class="help-inline">
{{ _('Enter your LDAP/Active Directory password.') }}
</span>
</div>
{% elif password_required %}
<div class="input-box password-div">
<input id="id_password" class="required" type="password" name="password" autocomplete="new-password"
value="{% if form.password.value() %}{{ form.password.value() }}{% endif %}"
data-min-length="{{password_min_length}}"
data-max-length="{{ password_max_length }}"
data-min-guesses="{{password_min_guesses}}" required />
<label for="id_password" class="inline-block">{{ _('Password') }}</label>
<i class="zulip-icon zulip-icon-hide password_visibility_toggle" role="button" tabindex="0"></i>
{% if full_name %}
<span class="help-inline">
{{ _('This is used for mobile applications and other tools that require a password.') }}
</span>
{% endif %}
{% if form.password.errors %}
{% for error in form.password.errors %}
<p class="help-inline text-error">{{ error }}</p>
{% endfor %}
{% endif %}
<div class="progress" id="pw_strength" title="{{ _('Password strength') }}">
<div class="bar bar-danger" style="width: 10%;"></div>
</div>
</div>
{% endif %}
</fieldset>
{% if default_stream_groups %}
<hr />
<div class="default-stream-groups">
<p>{{ _('What are you interested in?') }}</p>
{% for default_stream_group in default_stream_groups %}
<div class="input-group">
<label for="id_default_stream_group__{{ default_stream_group.id }}"
class="inline-block checkbox">
<input class="inline-block" type="checkbox"
name="default_stream_group"
id="id_default_stream_group__{{ default_stream_group.id }}" value="{{ default_stream_group.name }}"
{% if "default_stream_group" in form.data and default_stream_group.id in form.data.getlist('default_stream_group') %} checked {% endif %} />
<span class="rendered-checkbox"></span>
{% set comma = joiner(", ") %}
<span class="default_stream_group_name inline-block"
title="{{ default_stream_group.description }}">
{{ default_stream_group.name }}
</span>
(
{%- for stream in default_stream_group.streams.all() -%}
{{- comma() -}} <span class="stream_name inline-block">#{{ stream.name }}</span>
{%- endfor -%}
)
</label>
</div>
{% endfor %}
</div>
<hr />
{% endif %}
{% if creating_new_realm %}
{% include 'zerver/create_realm/found_zulip_form_field.html' %}
{% endif %}
<div class="input-group">
{% if terms_of_service %}
{% include 'zerver/create_user/terms_of_service_form_field.html' %}
{% endif %}
{% if corporate_enabled %}
<div class="input-group marketing-emails">
<label for="id_enable_marketing_emails" class="inline-block checkbox marketing_emails_checkbox">
<input id="id_enable_marketing_emails" type="checkbox" name="enable_marketing_emails"
checked="checked" />
<span class="rendered-checkbox"></span>
{% trans %}Subscribe me to Zulip's low-traffic newsletter (a few emails a year).{% endtrans %}
</label>
</div>
{% endif %}
<div class="register-button-box">
<button class="register-button" type="submit">
<span>{{ _('Sign up') }}</span>
<object class="loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
<input type="hidden" name="next" value="{{ next }}" />
</div>
</div>
</form>
</div>
</div>
{% if not creating_new_realm %}
{% include 'zerver/create_user/change_email_address_visibility_modal.html' %}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,21 @@
<div class="input-group terms-of-service">
{#
This is somewhat subtle.
Checkboxes have a name and value, and when the checkbox is ticked, the form posts
with name=value. If the checkbox is unticked, the field just isn't present at all.
This is distinct from 'checked', which determines whether the checkbox appears
at all. (So, it's not symmetric to the code above.)
#}
<label for="id_terms" class="inline-block checkbox">
<input id="id_terms" class="required" type="checkbox" name="terms"
{% if form.terms.value() %}checked="checked"{% endif %} />
<span class="rendered-checkbox"></span>
{% trans %}I agree to the <a href="{{ root_domain_url }}/policies/terms" target="_blank" rel="noopener noreferrer">Terms of Service</a>.{% endtrans %}
</label>
{% if form.terms.errors %}
{% for error in form.terms.errors %}
<p class="error help-inline alert alert-error">{{ error }}</p>
{% endfor %}
{% endif %}
</div>

View File

@@ -0,0 +1,71 @@
{% extends "zerver/portico_signup.html" %}
{% block title %}
<title>{{ _("Deactivated organization") }} | Zulip</title>
{% endblock %}
{% block customhead %}
{{ super() }}
<meta http-equiv="refresh" content="60;URL='/'" />
{% endblock %}
{% block portico_content %}
<div class="app portico-page">
<div class="app-main portico-page-container center-block flex full-page account-creation new-style">
<div class="inline-block">
<div class="get-started">
{% if deactivated_redirect %}
<h1>{{ _("Organization moved") }}</h1>
{% else %}
<h1>{{ _("Deactivated organization") }}</h1>
{% endif %}
</div>
<div class="white-box deactivated-realm-container">
<p>
{% if deactivated_redirect %}
{% trans %}
This organization has moved to <a href="{{ deactivated_redirect }}">{{ deactivated_redirect }}</a>.
{% endtrans %}
{% if auto_redirect_to %}
{% trans %}
This page will automatically redirect to the <a href="{{ auto_redirect_to }}" id="deactivated-org-auto-redirect">new URL</a> in <span id="deactivated-org-auto-redirect-countdown">5</span> seconds.
{% endtrans %}
{% endif %}
{% elif realm_data_deleted %}
{{ _("This organization has been deactivated, and all organization data has been deleted.") }}
{% if corporate_enabled %}
{% trans %}
You can <a href="mailto:{{ support_email }}">contact Zulip support</a> to inquire about reusing this URL for a new organization.
{% endtrans %}
{% else %}
{% trans %}
You can <a href="mailto:{{ support_email }}">contact this Zulip server's administrators</a> to inquire about reusing this URL for a new organization.
{% endtrans %}
{% endif %}
{% else %}
{{ _("This organization has been deactivated.") }}
{% if corporate_enabled %}
{% trans %}
If you are an owner of this organization, you can <a href="mailto:{{ support_email }}">contact Zulip support</a> to reactivate it.
{% endtrans %}
<br /><br />
{% trans %}
If you're a member of the organization and want information about why it has been deactivated, please reach out to the organization's administrators directly.
{% endtrans %}
{% else %}
{% trans %}
If you are an owner of this organization, you can <a href="mailto:{{ support_email }}">contact this Zulip server's administrators</a> to reactivate it.
{% endtrans %}
{% endif %}
{% endif %}
</p>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,33 @@
{% extends "zerver/portico.html" %}
{% set entrypoint = "desktop-login" %}
{% block title %}
<title>{{ _("Finish desktop app login") }} | Zulip</title>
{% endblock %}
{% block portico_content %}
<div class="flex new-style">
<div class="desktop-redirect-box">
<h1>{% trans %}Finish desktop login{% endtrans %}</h1>
<div class="white-box">
<p class="copy-token-info">{% trans %}Use your web browser to finish logging in, then come back here to paste in your login token.{% endtrans %}</p>
<form id="form" action="blob:">
<span class="input-box">
<input id="token" placeholder="{% trans %}Paste token here{% endtrans %}" type="text"/>
</span>
<button id="submit" disabled>{% trans %}Finish{% endtrans %}</button>
</form>
<p id="bad-token" hidden>
{% trans %}Incorrect token.{% endtrans %}
</p>
<p id="done" hidden>
{% trans %}Token accepted. Logging you in…{% endtrans %}
</p>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,23 @@
{% extends "zerver/portico.html" %}
{% set entrypoint = "desktop-redirect" %}
{% block title %}
<title>{{ _("Log in to desktop app") }} | Zulip</title>
{% endblock %}
{% block content %}
<div class="flex new-style">
<div class="desktop-redirect-box white-box">
<img class="avatar desktop-redirect-image" src="{{ realm_icon_url }}" alt=""/><br />
<p class="copy-token-info">{% trans %}Copy this login token and return to your Zulip app to finish logging in:{% endtrans %}</p>
<p>
<span class="input-box">
<input id="desktop-data" value="{{ desktop_data }}" type="text" readonly />
</span>
<button id="copy" tabindex="0" data-clipboard-target="#desktop-data">{% trans %}Copy{% endtrans %}</button>
</p>
<p>{% trans %}You may then close this window.{% endtrans %}</p>
<p><a href="{{ browser_url }}">{% trans %}Or, continue in your browser.{% endtrans %}</a></p>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,6 @@
{% if development_environment %}
<div class="alert alert-info" style="display:inline-block;">
In the development environment, outgoing emails are logged to
<a href="/emails">/emails</a>.
</div>
{% endif %}

View File

@@ -0,0 +1,57 @@
{% extends "zerver/portico.html" %}
{% set entrypoint = "dev-help" %}
{% block title %}
<title>Help center server not running | Zulip Dev</title>
{% endblock %}
{% block portico_content %}
<div class="dev-help-page flex">
<div class="white-box markdown">
{% if mdx_file_exists %}
<h2 class="dev-help-header">Help center server not running</h2>
<p>
To minimize resource requirements for the development
environment, the help center's development server does
not run by default. Below are our recommendations for
accessing this help center page:
</p>
<ul>
<li>
<b>Quick reference</b>: If you aren't planning to modify the help center, you can
<a target="_blank" rel="noopener noreferrer"
href="https://zulip.com/help/{{ subpath }}">view it on
zulip.com</a>. Pages may be slightly behind the version
currently in <code>main</code>.
</li>
<li>
<b>Up-to-date reference</b>: You can
<a target="_blank" rel="noopener noreferrer" href="{{
raw_url }}">view the current raw MDX file</a>, which is recommended for documentation
that touches brand new or recently modified features.
</li>
<li>
<b>Modifying the help center</b>:
{% include "zerver/development/help_center_instructions_macro.html" %}
</li>
</ul>
{% else %}
<p class="invalid-path-error">
This is not a valid help path and not a valid MDX file. Please re-check the URL subpath you have provided.
</p>
{% endif %}
<div class="dev-help-actions">
{% if mdx_file_exists %}
<a target="_blank" rel="noopener noreferrer" href="https://zulip.com/help/{{ subpath }}" class="dev-help-action-button">
View page on zulip.com
</a>
<a target="_blank" rel="noopener noreferrer" href="{{ raw_url }}" class="dev-help-action-button">
View page source
</a>
{% endif %}
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,125 @@
{% extends "zerver/portico.html" %}
{% set entrypoint = "dev-login" %}
{% block title %}
<title>Log in | Zulip Dev</title>
{% endblock %}
{# Login page. #}
{% block portico_content %}
<!-- The following empty tag has unique data-page-id so that this
page can be easily identified in it's respective JavaScript file -->
<div data-page-id="dev-login"></div>
<div class="app login-page flex full-page">
<div class="app-main login-page-container dev-login white-box">
{% if current_realm %}
<h4 class="login-page-header">Click on a user to log in to {{ current_realm.name }}!</h4>
{% else %}
<h4 class="login-page-header">Click on a user to log in!</h4>
{% endif %}
<p class="devlogin_subheader">(Browse the <a href="/devtools">developer tools</a> or visit the <a href="/login/{% if next %}?next={{ next|urlencode }}{% endif %}">normal login page</a>.)</p>
<form name="direct_login_form" id="direct_login_form" method="post" class="login-form">
<input type="hidden" name="next" value="{{ next }}" />
<div class="controls">
<div class="group">
{% if realm_web_public_access_enabled %}
<h2>{{_('Anonymous user') }}</h2>
<p>
<input type="submit" formaction="{{ current_realm.url }}{{ url('login-local') }}"
name="prefers_web_public_view" class="dev-button dev-login-button" value="Anonymous login" />
</p>
{% endif %}
<h2>{{_('Owners') }}</h2>
{% if direct_owners %}
{% for direct_owner in direct_owners %}
<p>
<button type="submit" formaction="{{ direct_owner.realm.url }}{{ url('login-local') }}"
name="direct_email" class="dev-button dev-login-button" value="{{ direct_owner.delivery_email }}">
{% if direct_owner.realm.demo_organization_scheduled_deletion_date %}
{{ direct_owner.full_name }}
{% else %}
{{ direct_owner.delivery_email }}
{% endif %}
</button>
</p>
{% endfor %}
{% else %}
<p>No owners found in this realm</p>
{% endif %}
<h2>{{ _('Administrators') }}</h2>
{% if direct_admins %}
{% for direct_admin in direct_admins %}
<p>
<input type="submit" formaction="{{ direct_admin.realm.url }}{{ url('login-local') }}"
name="direct_email" class="dev-button dev-login-button" value="{{ direct_admin.delivery_email }}" />
</p>
{% endfor %}
{% else %}
<p>No administrators found in this realm</p>
{% endif %}
<h2>{{ _('Moderators') }}</h2>
{% if direct_moderators %}
{% for direct_moderator in direct_moderators %}
<p>
<input type="submit" formaction="{{ direct_moderator.realm.url }}{{ url('login-local') }}"
name="direct_email" class="dev-button dev-login-button" value="{{ direct_moderator.delivery_email }}" />
</p>
{% endfor %}
{% else %}
<p>No moderators found in this realm</p>
{% endif %}
<h2>{{ _('Guest users') }}</h2>
{% if guest_users %}
{% for guest_user in guest_users %}
<p>
<input type="submit" formaction="{{ guest_user.realm.url }}{{ url('login-local') }}"
name="direct_email" class="dev-button dev-login-button" value="{{ guest_user.delivery_email }}" />
</p>
{% endfor %}
{% else %}
<p>No guest users found in this realm</p>
{% endif %}
</div>
<div class="group">
<h2>{{ _('Normal users') }}</h2>
{% if direct_users %}
{% for direct_user in direct_users %}
<p>
<input type="submit" formaction="{{ direct_user.realm.url }}{{ url('login-local') }}"
name="direct_email" class="dev-button dev-login-button" value="{{ direct_user.delivery_email }}" />
</p>
{% endfor %}
{% else %}
<p>No normal users found in this realm</p>
{% endif %}
</div>
</div>
</form>
<form name="change_realm" action="{{ url('login_page') }}" method="post">
{{ csrf_input }}
<h2>Realm</h2>
<select class="bootstrap-focus-style" name="new_realm" onchange="this.form.submit()">
<option value="all_realms" {% if not current_realm %}selected="selected"{% endif %}>All realms</option>
{% for realm in all_realms %}
<option value="{{realm.string_id}}" {% if current_realm == realm %}selected="selected"{% endif %}>{{realm.name}}</option>
{% endfor %}
</select>
</form>
<div id="devtools-wrapper">
<div id="devtools-registration">
<form name="register_dev_user" action="{{ url('register_dev_user') }}" method="POST">
<input type="submit" class="dev-button dev-create-button" value="Create new user" />
</form>
<form name="register_dev_realm" action="{{ url('register_dev_realm') }}" method="POST">
<input type="submit" class="dev-button dev-create-button" value="Create new realm" />
</form>
<form name="register_demo_dev_realm" action="{{ url('register_demo_dev_realm') }}" method="POST">
<input type="submit" class="dev-button dev-create-button" value="Create demo organization" />
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,179 @@
{% extends "zerver/portico.html" %}
{% block title %}
<title>Development tools | Zulip Dev</title>
{% endblock %}
{# Login page. #}
{% block portico_content %}
<div class="app flex full-page">
<div id="devtools-page" class="markdown">
<h1>Development tools</h1>
<p>
This page describes development-specific URLs and commands that may
come in handy. Make sure your development server is running when you
visit the pages linked below.
</p>
<h2>General</h2>
<table class="table table-striped table-rounded table-bordered">
<thead>
<tr>
<th>URL</th>
<th>Command</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="/devtools/integrations">/devtools/integrations</a></td>
<td>None needed</td>
<td>Test incoming webhook integrations</td>
</tr>
<tr>
<td><a href="/emails">/emails</a></td>
<td>None needed</td>
<td>View outgoing and example emails.</td>
</tr>
<tr>
<td><a href="/digest">/digest</a></td>
<td>None needed</td>
<td>View sample digest email.</td>
</tr>
<tr>
<td><a href="/docs/index.html">/docs/index.html</a></td>
<td><code>./tools/build-docs</code></td>
<td>Developer and production documentation (ReadTheDocs) built locally</td>
</tr>
<tr>
<td><a href="/stats/realm/analytics/">/stats/realm/analytics/</a></td>
<td><code>./manage.py populate_analytics_db</code><br />
Run the command after changing analytics data population logic.
</td>
<td>View the /stats page with some pre-populated data</td>
</tr>
</tbody>
</table>
<h2>Design system</h2>
<table class="table table-striped table-rounded table-bordered">
<thead>
<tr>
<th>URL</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="/devtools/buttons">/devtools/buttons</a></td>
<td>Test button styles</td>
</tr>
<tr>
<td><a href="/devtools/banners">/devtools/banners</a></td>
<td>Test banner styles</td>
</tr>
<tr>
<td><a href="/devtools/inputs">/devtools/inputs</a></td>
<td>Test input styles</td>
</tr>
</tbody>
</table>
<h2>Test coverage</h2>
<table class="table table-striped table-rounded table-bordered">
<thead>
<tr>
<th>URL</th>
<th>Command</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="/coverage/index.html">/coverage/index.html</a></td>
<td><code>./tools/test-backend --coverage</code></td>
<td>Backend (Django) test coverage report</td>
</tr>
<tr>
<td><a href="/node-coverage/index.html">/node-coverage/index.html</a></td>
<td><code>./tools/test-js-with-node --coverage</code></td>
<td>Frontend (node) test coverage report</td>
</tr>
</tbody>
</table>
<h2>Useful management commands</h2>
<p>Development-specific <a href="https://zulip.readthedocs.io/en/latest/production/management-commands.html">management commands</a> live in <code>zilencer/management/commands</code>. Highlights include:</p>
<ul>
<li><code>./manage.py populate_db</code>: Rebuilds database. Has options to, for example, create 3K users for testing.</li>
<li><code>./manage.py mark_all_messages_unread</code>: Useful for testing reading messages.</li>
<li><code>./manage.py send_zulip_update_announcements</code>: Send <a href="https://zulip.com/help/configure-automated-notices#zulip-update-announcements">Zulip
update notices</a> drafted in <code>zerver/lib/zulip_update_announcements.py</code>.</li>
<li><code>./manage.py add_mock_conversation</code>: Add test messages, streams, images, emoji, etc.
into the dev environment. First edit <code>zilencer/management/commands/add_mock_conversation.py</code>
to add the data you're testing.
</li>
</ul>
<p>We also have
<a href="https://zulip.readthedocs.io/en/latest/development/authentication.html">documentation on testing LDAP, Google &amp; GitHub authentication</a> in the development environment.
</p>
<h2>Modifying and running the help center</h2>
{% include "zerver/development/help_center_instructions_macro.html" %}
<h2>Viewing error pages</h2>
<table class="table table-striped table-rounded table-bordered">
<thead>
<tr>
<th>URL</th>
<th>Command</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="/webpack/5xx.html">/webpack/5xx.html</a></td>
<td>None needed</td>
<td>Error 5xx page served by nginx (used when Django is totally broken)</td>
</tr>
<tr>
<td><a href="/errors/404">/errors/404</a></td>
<td>None needed</td>
<td>Error 404 page served by Django</td>
</tr>
<tr>
<td><a href="/errors/5xx">/errors/5xx</a></td>
<td>None needed</td>
<td>Error 5xx page served by Django</td>
</tr>
<tr>
<td><a href="/accounts/do_confirm/invalid">/accounts/do_confirm/invalid</a></td>
<td>None needed</td>
<td>Invalid confirmation link page</td>
</tr>
</tbody>
</table>
<h2>Connecting to the local PostgreSQL database</h2>
<ul>
<li>
<code>./manage.py dbshell</code>: Connect to
PostgreSQL database via your terminal.
</li>
<li>
<code>provision</code> creates a <code>~/.pgpass</code> file,
so <code>psql -U zulip -h localhost</code> works too.
</li>
<li>
<p>
To connect using a graphical PostgreSQL client
like <a href="https://www.pgadmin.org/">pgAdmin</a>,
use the following credentials:
</p>
<ul>
<li>Host: 127.0.0.1 (don't use localhost)</li>
<li>Maintenance database: zulip</li>
<li>Username: zulip</li>
<li>password: stored as <code>local_database_password</code> in <code>zulip/zproject/dev-secrets.conf</code></li>
</ul>
</li>
</ul>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,77 @@
{% extends "zerver/base.html" %}
{% set entrypoint = "dev-email-log" %}
{% block title %}
<title>Email log | Zulip Dev</title>
{% endblock %}
{% block content %}
<div class="container" id="dev-email-log-container">
<div class="dev-email-log-header">
<div class="dev-email-log-actions">
All emails sent in the Zulip development environment are logged here. <a href="/emails/clear">Clear this log</a>
| <a href="/emails/generate">Manually generate most emails</a>
| <a href="#" class="open-forward-email-modal">Forward emails to an email account</a>
</div>
<div class="dev-email-log-text-only">
<label>
<input type="checkbox" autocomplete="off" id="toggle"/>
<strong>Show text only version</strong>
</label>
</div>
</div>
<div class="dev-email-log-content">
{{ log |safe }}
</div>
<div id="forward_email_modal" class="micromodal" aria-hidden="true">
<div class="modal__overlay" tabindex="-1">
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="forward_email_modal_label">
<header class="modal__header">
<div class="modal__header-content">
<h1 id="forward_email_modal_label" class="modal__title dialog_heading">
{{ _('Forward emails to an email account') }}
</h1>
</div>
<button type="button" class="modal__close" aria-label="{{ _('Close modal') }}" tabindex="0" data-micromodal-close>
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
</header>
<main class="modal__content">
<div class="input-group">
<form id="smtp_form">
{{ csrf_input }}
<div class="dev-forward-email-alert" id="smtp_form_status">
Updated successfully.
</div>
<label for="forward">
Forwards all emails sent in the development environment to an external mail account.
</label>
<label class="radio">
<input name="forward" type="radio" value="enabled" {% if forward_address %}checked{% endif %}/>Yes
</label>
<label class="radio">
<input name="forward" type="radio" value="disabled" {% if not forward_address %}checked{% endif %}/>No
</label>
<div id="forward_address_sections" {% if not forward_address %}class="hide"{% endif %} >
<label for="forward_address"><strong>Address to which emails should be forwarded</strong></label>
<input type="text" id="address" name="forward_address" placeholder="eg: your-email@example.com" value="{{forward_address}}"/>
</div>
<div class="dev-forward-email-alert">
You must set up SMTP as described
<a target="_blank" rel="noopener noreferrer" href="https://zulip.readthedocs.io/en/latest/subsystems/email.html#development-and-testing"> here</a>
first before enabling this.
</div>
</form>
</div>
</main>
<footer class="modal__footer">
<button class="modal__button dialog_exit_button" aria-label="{{ '(Close this dialog window)' }}" data-micromodal-close>{{ _('Close') }}</button>
<button class="modal__button dialog_submit_button">
<span>{{ _('Update') }}</span>
</button>
</footer>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,23 @@
If you're making changes to the help center files, be sure to <b>test</b> and
provide screenshots in your pull request description. As with other code,
untested documentation is often buggy.
<ul>
<li>
To run just the help center dev server without
running the rest of the Zulip app, use
<code>./tools/run-dev --only-help-center</code>.
</li>
<li>
To run the help center dev server alongside the
Zulip app, use
<code>./tools/run-dev --help-center-dev-server</code> (requires more resources).
</li>
<li>
To test help center search, run <code>./tools/build-help-center</code> followed by
<code>./tools/run-dev --help-center-static-build</code>. Hot reloads won't
work: rerun <code>./tools/build-help-center</code>
and reload your browser to see updates. Search will not
work with other methods of running the help center.
</li>
</ul>

View File

@@ -0,0 +1,113 @@
{% extends "zerver/portico.html" %}
{% set entrypoint = "dev-integrations-panel" %}
{% block title %}
<title>Integrations developer panel | Zulip Dev</title>
{% endblock %}
{% block customhead %}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{% endblock %}
{% block portico_content %}
<div class="header portico-header">
<div class="header-main top-navbar">
<div>
<a class="brand logo">
<svg role="img" aria-label="{{ _('Zulip') }}" xmlns="http://www.w3.org/2000/svg" viewBox="68.96 55.62 1742.12 450.43" height="25">
<path fill="hsl(0, 0%, 27%)" d="M473.09 122.97c0 22.69-10.19 42.85-25.72 55.08L296.61 312.69c-2.8 2.4-6.44-1.47-4.42-4.7l55.3-110.72c1.55-3.1-.46-6.91-3.64-6.91H129.36c-33.22 0-60.4-30.32-60.4-67.37 0-37.06 27.18-67.37 60.4-67.37h283.33c33.22-.02 60.4 30.3 60.4 67.35zM129.36 506.05h283.33c33.22 0 60.4-30.32 60.4-67.37 0-37.06-27.18-67.37-60.4-67.37H198.2c-3.18 0-5.19-3.81-3.64-6.91l55.3-110.72c2.02-3.23-1.62-7.1-4.42-4.7L94.68 383.6c-15.53 12.22-25.72 32.39-25.72 55.08 0 37.05 27.18 67.37 60.4 67.37zm522.5-124.15l124.78-179.6v-1.56H663.52v-48.98h190.09v34.21L731.55 363.24v1.56h124.01v48.98h-203.7V381.9zm338.98-230.14V302.6c0 45.09 17.1 68.03 47.43 68.03 31.1 0 48.2-21.77 48.2-68.03V151.76h59.09V298.7c0 80.86-40.82 119.34-109.24 119.34-66.09 0-104.96-36.54-104.96-120.12V151.76h59.48zm244.91 0h59.48v212.25h104.18v49.76h-163.66V151.76zm297 0v262.01h-59.48V151.76h59.48zm90.18 3.5c18.27-3.11 43.93-5.44 80.08-5.44 36.54 0 62.59 7 80.08 20.99 16.72 13.22 27.99 34.99 27.99 60.64 0 25.66-8.55 47.43-24.1 62.2-20.21 19.05-50.15 27.6-85.13 27.6-7.77 0-14.77-.39-20.21-1.17v93.69h-58.7V155.26zm58.7 118.96c5.05 1.17 11.27 1.55 19.83 1.55 31.49 0 50.92-15.94 50.92-42.76 0-24.1-16.72-38.49-46.26-38.49-12.05 0-20.21 1.17-24.49 2.33v77.37z"/>
</svg>
</a>
</div>
<div class="centerpiece">Integrations developer panel</div>
<div class="top-links">
<a href="/">Go to Zulip</a>
</div>
</div>
</div>
<div class="pad-small"></div>
<div id="dev-panel">
<div class="row1">
<div>
<label for="bot_name"><b>Bot</b></label>
<select class="bootstrap-focus-style" id="bot_name">
<option value=""></option>
{% for bot in bots %}
<option value="{{ bot.api_key }}"> {{ bot.full_name }} </option>
{% endfor %}
</select>
</div>
<div>
<label><b>Integration</b></label>
<select class="bootstrap-focus-style" id="integration_name">
<option value=""></option>
{% for integration in integrations %}
<option value="{{ integration }}"> {{ integration }} </option>
{% endfor %}
</select>
</div>
<div>
<label for="fixture_name"><b>Fixture</b></label>
<select class="bootstrap-focus-style" id="fixture_name"></select>
</div>
<div>
<label class="optional"><b>Stream</b></label>
<input id="stream_name" type="text" />
</div>
<div>
<label class="optional"><b>Topic</b></label>
<input id="topic_name" type="text" />
</div>
</div>
<br />
<div class="row2">
<label for="URL"><b>URL</b> (automatically generated)</label>
<input id="URL" type="text" />
</div>
<br />
<div class="row3">
<label for="custom_http_headers"><b>Custom HTTP headers</b></label>
<textarea id="custom_http_headers"></textarea>
</div>
<br />
<div class="row4">
<div class="col1">
<div class="inline">
<label for="fixture_body"><b>Fixture body</b></label>
<span id="results_notice"></span>
</div>
<textarea id="fixture_body"></textarea>
<div class="buttons">
<button id="send_all_fixtures_button">Send all</button>
<button id="send_fixture_button">Send!</button>
</div>
</div>
<div class="col1">
<label for="idp-results"><b>Results</b></label>
<textarea id="idp-results" readonly></textarea>
</div>
</div>
</div>
<div class="pad-small"></div>
<input id="csrftoken" type="hidden" value="{{ csrf_token }}" />
{% endblock %}

View File

@@ -0,0 +1,211 @@
{% extends "zerver/base.html" %}
{% set entrypoint = "showroom" %}
{% block title %}
<title>{{ doc_root_title }} | Zulip Dev</title>
{% endblock %}
{% block content %}
<div class="portico-container" data-platform="{{ platform }}">
<div class="portico-wrap">
{% include 'zerver/portico-header.html' %}
<div class="app portico-page">
<div class="banner-wrapper" id="showroom_component_banner_navbar_alerts_wrapper"></div>
<div class="app-main portico-page-container">
<div class="showroom-wrapper">
<div class="banner-wrapper" id="showroom_component_banner_default_wrapper"></div>
<section class="showroom-controls-section">
<div class="showroom-controls-label">Theme Settings</div>
<div class="showroom-controls">
<div class="showroom-control">
<span class="showroom-control-label">Dark Theme</span>
<div role="group" class="tab-picker showroom-control-setting">
<input type="radio" data-theme="dark" id="showroom_enable_dark_theme_banners" class="tab-option" name="showroom-dark-theme-select"/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="showroom_enable_dark_theme_banners" tabindex="0">
<span>Enable</span>
</label>
<input type="radio" data-theme="light" id="showroom_disable_dark_theme_banners" class="tab-option" name="showroom-dark-theme-select" checked/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="showroom_disable_dark_theme_banners" tabindex="0">
<span>Disable</span>
</label>
<span class="slider"></span>
</div>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Select Background</span>
<select class="showroom-control-element showroom-control-setting select_background">
{% for background in background_colors %}
<option value="{{ background.css_var }}" {% if background.css_var == "--color-background" %}selected{% endif %}>{{ background.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="showroom-controls-label">Banner Settings</div>
<div class="showroom-controls">
<div class="showroom-control">
<span class="showroom-control-label">Alert Banner Type</span>
<select class="showroom-control-element showroom-control-setting" id="banner_select_type"></select>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Banner Intent</span>
<select class="showroom-control-element showroom-control-setting" id="showroom_component_banner_select_intent"></select>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Banner Label</span>
<input class="showroom-control-element showroom-control-setting" type="text" id="banner_label" />
</div>
<div class="showroom-control">
<span class="showroom-control-label">Banner Close Button</span>
<div role="group" class="tab-picker showroom-control-setting">
<input type="radio" id="enable_banner_close_button" class="tab-option" name="banner-close-button-select"/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="enable_banner_close_button" tabindex="0">
<span>Enable</span>
</label>
<input type="radio" id="disable_banner_close_button" class="tab-option" name="banner-close-button-select" checked/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="disable_banner_close_button" tabindex="0">
<span>Disable</span>
</label>
<span class="slider"></span>
</div>
</div>
</div>
<div class="showroom-controls-label">Solid Button Settings</div>
<div class="showroom-controls">
<div class="showroom-control">
<span class="showroom-control-label">Button</span>
<div role="group" class="tab-picker showroom-control-setting">
<input type="radio" id="enable_solid_button" class="tab-option" name="solid-button-select"/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="enable_solid_button" tabindex="0">
<span>Enable</span>
</label>
<input type="radio" id="disable_solid_button" class="tab-option" name="solid-button-select" checked/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="disable_solid_button" tabindex="0">
<span>Disable</span>
</label>
<span class="slider"></span>
</div>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Button Icon</span>
<div role="group" class="tab-picker showroom-control-setting">
<input type="radio" id="enable_solid_button_icon" class="tab-option" name="solid-button-icon-select"/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="enable_solid_button_icon" tabindex="0">
<span>Enable</span>
</label>
<input type="radio" id="disable_solid_button_icon" class="tab-option" name="solid-button-icon-select" checked/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="disable_solid_button_icon" tabindex="0">
<span>Disable</span>
</label>
<span class="slider"></span>
</div>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Select Icon</span>
<select class="showroom-control-element showroom-control-setting" id="solid_button_select_icon">
{% for icon in icons %}
<option value="{{ icon }}" {% if icon == "move-alt" %}selected{% endif %}>{{ icon }}</option>
{% endfor %}
</select>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Button Text</span>
<input class="showroom-control-element showroom-control-setting" type="text" id="solid_button_text" />
</div>
</div>
<div class="showroom-controls-label">Subtle Button Settings</div>
<div class="showroom-controls">
<div class="showroom-control">
<span class="showroom-control-label">Button</span>
<div role="group" class="tab-picker showroom-control-setting">
<input type="radio" id="enable_subtle_button" class="tab-option" name="subtle-button-select"/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="enable_subtle_button" tabindex="0">
<span>Enable</span>
</label>
<input type="radio" id="disable_subtle_button" class="tab-option" name="subtle-button-select" checked/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="disable_subtle_button" tabindex="0">
<span>Disable</span>
</label>
<span class="slider"></span>
</div>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Button Icon</span>
<div role="group" class="tab-picker showroom-control-setting">
<input type="radio" id="enable_subtle_button_icon" class="tab-option" name="subtle-button-icon-select"/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="enable_subtle_button_icon" tabindex="0">
<span>Enable</span>
</label>
<input type="radio" id="disable_subtle_button_icon" class="tab-option" name="subtle-button-icon-select" checked/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="disable_subtle_button_icon" tabindex="0">
<span>Disable</span>
</label>
<span class="slider"></span>
</div>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Select Icon</span>
<select class="showroom-control-element showroom-control-setting" id="subtle_button_select_icon">
{% for icon in icons %}
<option value="{{ icon }}" {% if icon == "move-alt" %}selected{% endif %}>{{ icon }}</option>
{% endfor %}
</select>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Button Text</span>
<input class="showroom-control-element showroom-control-setting" type="text" id="subtle_button_text" />
</div>
</div>
<div class="showroom-controls-label">Text Button Settings</div>
<div class="showroom-controls">
<div class="showroom-control">
<span class="showroom-control-label">Button</span>
<div role="group" class="tab-picker showroom-control-setting">
<input type="radio" id="enable_text_button" class="tab-option" name="text-button-select"/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="enable_text_button" tabindex="0">
<span>Enable</span>
</label>
<input type="radio" id="disable_text_button" class="tab-option" name="text-button-select" checked/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="disable_text_button" tabindex="0">
<span>Disable</span>
</label>
<span class="slider"></span>
</div>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Button Icon</span>
<div role="group" class="tab-picker showroom-control-setting">
<input type="radio" id="enable_text_button_icon" class="tab-option" name="text-button-icon-select"/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="enable_text_button_icon" tabindex="0">
<span>Enable</span>
</label>
<input type="radio" id="disable_text_button_icon" class="tab-option" name="text-button-icon-select" checked/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="disable_text_button_icon" tabindex="0">
<span>Disable</span>
</label>
<span class="slider"></span>
</div>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Select Icon</span>
<select class="showroom-control-element showroom-control-setting" id="text_button_select_icon">
{% for icon in icons %}
<option value="{{ icon }}" {% if icon == "move-alt" %}selected{% endif %}>{{ icon }}</option>
{% endfor %}
</select>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Button Text</span>
<input class="showroom-control-element showroom-control-setting" type="text" id="text_button_text" />
</div>
</div>
</section>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,232 @@
{% extends "zerver/base.html" %}
{% set entrypoint = "showroom" %}
{% block title %}
<title>{{ doc_root_title }} | Zulip Dev</title>
{% endblock %}
{% block content %}
<div class="portico-container" data-platform="{{ platform }}">
<div class="portico-wrap">
{% include 'zerver/portico-header.html' %}
<div class="app portico-page">
<div class="app-main portico-page-container">
<div class="showroom-wrapper">
<div class="showroom-button-grid">
<div class="showroom-component-button-intent-group">
<div class="showroom-component-action-button-label">Action Buttons</div>
<div class="showroom-component-icon-button-label">Icon Buttons</div>
</div>
<div class="showroom-component-button-intent-group">
<div class="showroom-component-button-intent-label">Neutral Variant</div>
<div class="showroom-component-action-button-group">
<button class="action-button action-button-solid-neutral" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
<button class="action-button action-button-subtle-neutral" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
<button class="action-button action-button-text-neutral" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
</div>
<div class="showroom-component-icon-button-group">
<button class="icon-button icon-button-neutral" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
</button>
<button class="icon-button icon-button-square icon-button-neutral" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
</button>
</div>
</div>
<div class="showroom-component-button-intent-group">
<div class="showroom-component-button-intent-label">Brand Variant</div>
<div class="showroom-component-action-button-group">
<button class="action-button action-button-solid-brand" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
<button class="action-button action-button-subtle-brand" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
<button class="action-button action-button-text-brand" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
</div>
<div class="showroom-component-icon-button-group">
<button class="icon-button icon-button-brand" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
</button>
<button class="icon-button icon-button-square icon-button-brand" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
</button>
</div>
</div>
<div class="showroom-component-button-intent-group">
<div class="showroom-component-button-intent-label">Info Variant</div>
<div class="showroom-component-action-button-group">
<button class="action-button action-button-solid-info" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
<button class="action-button action-button-subtle-info" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
<button class="action-button action-button-text-info" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
</div>
<div class="showroom-component-icon-button-group">
<button class="icon-button icon-button-info" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
</button>
<button class="icon-button icon-button-square icon-button-info" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
</button>
</div>
</div>
<div class="showroom-component-button-intent-group">
<div class="showroom-component-button-intent-label">Success Variant</div>
<div class="showroom-component-action-button-group">
<button class="action-button action-button-solid-success" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
<button class="action-button action-button-subtle-success" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
<button class="action-button action-button-text-success" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
</div>
<div class="showroom-component-icon-button-group">
<button class="icon-button icon-button-success" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
</button>
<button class="icon-button icon-button-square icon-button-success" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
</button>
</div>
</div>
<div class="showroom-component-button-intent-group">
<div class="showroom-component-button-intent-label">Warning Variant</div>
<div class="showroom-component-action-button-group">
<button class="action-button action-button-solid-warning" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
<button class="action-button action-button-subtle-warning" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
<button class="action-button action-button-text-warning" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
</div>
<div class="showroom-component-icon-button-group">
<button class="icon-button icon-button-warning" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
</button>
<button class="icon-button icon-button-square icon-button-warning" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
</button>
</div>
</div>
<div class="showroom-component-button-intent-group">
<div class="showroom-component-button-intent-label">Danger Variant</div>
<div class="showroom-component-action-button-group">
<button class="action-button action-button-solid-danger" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
<button class="action-button action-button-subtle-danger" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
<button class="action-button action-button-text-danger" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
<span class="action-button-label">Button joy</span>
</button>
</div>
<div class="showroom-component-icon-button-group">
<button class="icon-button icon-button-danger" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
</button>
<button class="icon-button icon-button-square icon-button-danger" tabindex=0>
<i class="zulip-icon zulip-icon-move-alt"></i>
</button>
</div>
</div>
</div>
<section class="showroom-controls-section">
<div class="showroom-controls-label">Controls</div>
<div class="showroom-controls">
<div class="showroom-control">
<span class="showroom-control-label">Dark Theme</span>
<div role="group" class="tab-picker">
<input type="radio" data-theme="dark" id="showroom_enable_dark_theme_buttons" class="tab-option" name="showroom-dark-theme-select"/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="showroom_enable_dark_theme_buttons" tabindex="0">
<span>Enable</span>
</label>
<input type="radio" data-theme="light" id="showroom_disable_dark_theme_buttons" class="tab-option" name="showroom-dark-theme-select" checked/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="showroom_disable_dark_theme_buttons" tabindex="0">
<span>Disable</span>
</label>
<span class="slider"></span>
</div>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Select Background</span>
<select class="showroom-control-element select_background">
{% for background in background_colors %}
<option value="{{ background.css_var }}" {% if background.css_var == "--color-background" %}selected{% endif %}>{{ background.name }}</option>
{% endfor %}
</select>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Action Button Icon</span>
<div role="group" class="tab-picker">
<input type="radio" id="enable_button_icon" class="tab-option" name="button-icon-select" checked/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="enable_button_icon" tabindex="0">
<span>Enable</span>
</label>
<input type="radio" id="disable_button_icon" class="tab-option" name="button-icon-select"/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="disable_button_icon" tabindex="0">
<span>Disable</span>
</label>
<span class="slider"></span>
</div>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Select Icon</span>
<select class="showroom-control-element" id="button_select_icon">
{% for icon in icons %}
<option value="{{ icon }}" {% if icon == "move-alt" %}selected{% endif %}>{{ icon }}</option>
{% endfor %}
</select>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Action Button Text</span>
<div class="showroom-control-setting showroom-control-setting-multiple">
<input class="showroom-control-element" type="text" id="button_text" />
<button class="showroom-control-element" id="clear_button_text">Reset</button>
</div>
</div>
</div>
</section>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,48 @@
{% extends "zerver/base.html" %}
{% set entrypoint = "showroom" %}
{% block title %}
<title>{{ doc_root_title }} | Zulip Dev</title>
{% endblock %}
{% block content %}
<div class="portico-container" data-platform="{{ platform }}">
<div class="portico-wrap">
{% include 'zerver/portico-header.html' %}
<div class="app portico-page">
<div class="app-main portico-page-container">
<div class="showroom-wrapper">
<div class="showroom-filter-input-container"></div>
<section class="showroom-controls-section">
<div class="showroom-controls-label">Theme Settings</div>
<div class="showroom-controls">
<div class="showroom-control">
<span class="showroom-control-label">Dark Theme</span>
<div role="group" class="tab-picker showroom-control-setting">
<input type="radio" data-theme="dark" id="showroom_enable_dark_theme_inputs" class="tab-option" name="showroom-dark-theme-select"/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="showroom_enable_dark_theme_inputs" tabindex="0">
<span>Enable</span>
</label>
<input type="radio" data-theme="light" id="showroom_disable_dark_theme_inputs" class="tab-option" name="showroom-dark-theme-select" checked/>
<label role="menuitemradio" class="tab-option-content showroom-control-element" for="showroom_disable_dark_theme_inputs" tabindex="0">
<span>Disable</span>
</label>
<span class="slider"></span>
</div>
</div>
<div class="showroom-control">
<span class="showroom-control-label">Select Background</span>
<select class="showroom-control-element showroom-control-setting select_background">
{% for background in background_colors %}
<option value="{{ background.css_var }}" {% if background.css_var == "--color-background" %}selected{% endif %}>{{ background.name }}</option>
{% endfor %}
</select>
</div>
</div>
</section>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,29 @@
{% extends "zerver/base.html" %}
{% set entrypoint = "digest" %}
{% block title %}
<title>{{ _("Digest") }} | Zulip</title>
{% endblock %}
{% block content %}
<div class="portico-wrap">
{% include 'zerver/portico-header.html' %}
</div>
<div class="digest-container">
<div class="digest-email-container">
<div class="portico-page digest-page-title">
<h1> Zulip digest </h1>
</div>
<div class="digest-email-html">
{{ inlined_digest_content|safe }}
<img id="digest-footer" src="{{ static('images/emails/footer.png') }}"/>
</div>
<br />
<br />
<h2 class="digest-page-title">Plain text version</h2>
<pre>{% include 'zerver/emails/digest.txt' %}</pre>
<div class="digest-address-link"> {{physical_address}}</div>
</div>
{% include 'zerver/footer.html' %}
</div>
{% endblock %}

View File

@@ -0,0 +1,48 @@
{% extends "zerver/portico-help.html" %}
{% set entrypoint = "help" %}
{# Zulip user and API documentation. #}
{% block title %}
<title>{{ PAGE_TITLE }}</title>
{% endblock %}
{% block portico_content %}
<div class="app help terms-page inline-block{% if page_is_api_center %} api-center{% endif %}">
<div class="sidebar">
<div class="content">
{{ sidebar_html }}
{% if not page_is_policy_center %}
<h1 class="home-link"><a href="/" class="no-underline">Back to Zulip</a></h1>
{% endif %}
</div>
</div>
<svg height="32px" class="hamburger" style="enable-background:new 0 0 32 32;" version="1.1" viewBox="0 0 32 32" width="32px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M4,10h24c1.104,0,2-0.896,2-2s-0.896-2-2-2H4C2.896,6,2,6.896,2,8S2.896,10,4,10z M28,14H4c-1.104,0-2,0.896-2,2 s0.896,2,2,2h24c1.104,0,2-0.896,2-2S29.104,14,28,14z M28,22H4c-1.104,0-2,0.896-2,2s0.896,2,2,2h24c1.104,0,2-0.896,2-2 S29.104,22,28,22z"></path>
</svg>
<div class="markdown">
<div class="content" id="main-content">
{% if page_is_policy_center %}
{{ render_markdown_path(article) }}
{% else %}
{{ render_markdown_path(article, context=api_url_context) }}
{% endif %}
<div class="documentation-footer">
<hr />
{% if corporate_enabled %}
{% if page_is_policy_center %}
<p>Please contact {{ support_email_html_tag }} with any questions about Zulip's policies.</p>
{% else %}
<p>Your feedback helps us make Zulip better for everyone! Please <a href="/help/contact-support">contact us</a> with questions, suggestions, and feature requests.</p>
{% endif %}
{% else %}
<p>Don't see an answer to your question? <a href="mailto:{{ support_email }}">Contact this Zulip server's administrators</a> for support.</p>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,27 @@
{% if from_email != envelope_from %}
<h4>Envelope-From: {{ envelope_from }}</h4>
{% endif %}
<h4>From: {{ from_email }}</h4>
<h4>Date: {{ date }}</h4>
{% if reply_to %}
<h4>Reply to:
{% for email in reply_to %}
{{ email }}&nbsp;
{% endfor %}
</h4>
{% endif %}
<h4>To:
{% for recipient in recipients %}
{{ recipient }}&nbsp;
{% endfor %}
</h4>
<h4>Subject: {{subject}}</h4>
<div class="email-html" style="display: block;">
{% autoescape off %}
{{ html_message }}
{% endautoescape %}
</div>
<div class="email-text" style="display: none;">
<pre>{{ body }}</pre>
</div>
<hr />

1
templates/zerver/emails/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
custom

View File

@@ -0,0 +1,54 @@
{% extends "zerver/emails/email_base_default.html" %}
{% block illustration %}
<img src="{{ email_images_base_url }}/email_logo.png" alt=""/>
{% endblock %}
{% block content %}
{% if realm_creation %}
<p>
{% trans %}Congratulations, you have created a new Zulip
organization: <b>{{ realm_name }}</b>.{% endtrans %}
</p>
{% else %}
<p>{{ _('Welcome to Zulip!') }}</p>
<p>
{% trans %}You've joined the Zulip organization <b>{{ realm_name }}</b>.
{% endtrans %}
</p>
{% endif %}
<p>
{% trans apps_page_link="https://zulip.com/apps/" %}You will use the following info to log into the Zulip web, <a href="{{ apps_page_link }}">mobile and desktop</a> apps:{% endtrans %}
</p>
<ul>
<li>{% trans organization_url=macros.link_tag(realm_url) %}Organization URL: {{ organization_url }}{% endtrans %}<br /></li>
{% if ldap %}
{% if ldap_username %}
<li>{% trans %}Your username: {{ ldap_username }}{% endtrans %}<br /></li>
{% else %}
<li>{{ _('Use your LDAP account to log in') }}<br /></li>
{% endif %}
{% else %}
<li>{% trans email=macros.email_tag(email) %}Your account email: {{ email }}{% endtrans %}<br /></li>
{% endif %}
</ul>
<p>
<a class="button" href="{{ realm_url }}">{{ _('Go to organization') }}</a>
</p>
<p>
{% trans %}If you are new to Zulip, check out our <a href="{{ getting_user_started_link }}">getting started guide</a>!{% endtrans %}
{% if is_realm_admin %}
{% trans %}We also have a guide for <a href="{{ getting_organization_started_link }}">moving your organization to Zulip</a>.{% endtrans %}
{% endif %}
</p>
<p>
{% if corporate_enabled %}
{% trans %}Questions? <a href="mailto:{{ support_email }}">Contact us</a> — we'd love to help!{% endtrans %}
{% else %}
{{macros.contact_us_self_hosted(support_email)}}
{% endif %}
</p>
{% endblock %}

View File

@@ -0,0 +1,9 @@
{% if realm_creation %}
{% trans -%}
{{ realm_name }} on Zulip: Your new organization details
{%- endtrans %}
{% else %}
{% trans -%}
{{ realm_name }} on Zulip: Your new account details
{%- endtrans %}
{% endif %}

View File

@@ -0,0 +1,35 @@
{{ _('Welcome to Zulip!') }}
{% if realm_creation %}
{% trans %}Congratulations, you have created a new Zulip organization: {{ realm_name }}.{% endtrans %}
{% else %}
{% trans %}You've joined the Zulip organization {{ realm_name }}.{% endtrans %}
{% endif %}
{% trans apps_page_link="https://zulip.com/apps/" %}You will use the following info to log into the Zulip web, mobile and desktop apps ({{ apps_page_link}}):{% endtrans %}
* {% trans organization_url=realm_url %}Organization URL: {{ organization_url }}{% endtrans %}
{% if ldap %}
{% if ldap_username %}
* {% trans %}Your username: {{ ldap_username }}{% endtrans %}
{% else %}
* {{ _('Use your LDAP account to log in') }}
{% endif %}
{% else %}
* {% trans %}Your account email: {{ email }}{% endtrans %}
{% endif %}
{% trans %}If you are new to Zulip, check out our getting started guide ({{ getting_user_started_link }})!{% endtrans %}
{% if is_realm_admin %}
{% trans %} We also have a guide for moving your organization to Zulip ({{ getting_organization_started_link }}).{% endtrans %}
{% endif %}
{% if corporate_enabled %}
{% trans %}Questions? Contact us at {{ support_email }} — we'd love to help!{% endtrans %}
{% else %}
{% trans %}If you have any questions, please contact this Zulip server's administrators at {{ support_email }}.{% endtrans %}
{% endif %}

View File

@@ -0,0 +1,14 @@
{% extends "zerver/emails/email_base_default.html" %}
{% block illustration %}
<img src="{{ email_images_base_url }}/email_logo.png" alt=""/>
{% endblock %}
{% block content %}
<p>{% trans %}Hi,{% endtrans %}</p>
<p>{% trans realm_url=macros.link_tag(realm_url), new_email=macros.email_tag(new_email) %}We received a request to add the email address {{ new_email }} to your Zulip demo organization account on {{ realm_url }}. To confirm this update and set a password for this account, please click below:{% endtrans %}
<a class="button" href="{{ activate_url }}">{{_('Confirm and set password') }}</a></p>
<p>{% trans support_email=macros.email_tag(support_email) %}If you did not request this change, please contact us immediately at {{ support_email }}.{% endtrans %}</p>
{% endblock %}

View File

@@ -0,0 +1 @@
{{ _("Verify your email address for your Zulip demo organization") }}

View File

@@ -0,0 +1,15 @@
{% trans -%}
Hi,
{%- endtrans %}
{% trans -%}
We received a request to add the email address {{ new_email }} to your Zulip demo organization account on {{ realm_url }}. To confirm this update and set a password for this account, please click below:
{%- endtrans %}
{{ activate_url }}
{% trans -%}
If you did not request this change, please contact us immediately at <{{ support_email }}>.
{%- endtrans %}

View File

@@ -0,0 +1,14 @@
{% extends "zerver/emails/email_base_default.html" %}
{% block illustration %}
<img src="{{ email_images_base_url }}/email_logo.png" alt=""/>
{% endblock %}
{% block content %}
<p>{% trans %}Hi,{% endtrans %}</p>
<p>{% trans realm_url=macros.link_tag(realm_url), old_email=macros.email_tag(old_email), new_email=macros.email_tag(new_email) %}We received a request to change the email address for the Zulip account on {{ realm_url }} from {{ old_email }} to {{ new_email }}. To confirm this change, please click below:{% endtrans %}
<a class="button" href="{{ activate_url }}">{{_('Confirm email change') }}</a></p>
<p>{% trans support_email=macros.email_tag(support_email) %}If you did not request this change, please contact us immediately at {{ support_email }}.{% endtrans %}</p>
{% endblock %}

View File

@@ -0,0 +1 @@
{% trans %}Verify your new email address for {{ organization_host }}{% endtrans %}

View File

@@ -0,0 +1,15 @@
{% trans -%}
Hi,
{%- endtrans %}
{% trans -%}
We received a request to change the email address for the Zulip account on {{ realm_url }} from {{ old_email }} to {{ new_email }}. To confirm this change, please click below:
{%- endtrans %}
{{ activate_url }}
{% trans -%}
If you did not request this change, please contact us immediately at <{{ support_email }}>.
{%- endtrans %}

View File

@@ -0,0 +1,36 @@
{% extends "zerver/emails/email_base_default.html" %}
{% block illustration %}
<img src="{{ email_images_base_url }}/registration_confirmation.png" alt=""/>
{% endblock %}
{% block content %}
{% if create_realm %}
<p>
{{ _("You have requested a new Zulip organization:") }}
</p>
<ul>
<li>{% trans %}Organization URL: {{ organization_url }}{% endtrans %}</li>
<li>{% trans %}Organization type: {{ organization_type }}{% endtrans %}</li>
</ul>
{% else %}
<p>
{{ _("You recently signed up for Zulip. Awesome!") }}
</p>
{% endif %}
<p>
{% if create_realm %}
{{ _("Click the button below to create the organization and register your account. You'll be able to update the information above if you like.") }}
{% else %}
{{ _("Click the button below to complete registration.") }}
{% endif %}
<a class="button" href="{{ activate_url }}">{{ _("Complete registration") }}</a>
</p>
<p>
{% if corporate_enabled %}
{{macros.contact_us_zulip_cloud(support_email)}}
{% else %}
{{macros.contact_us_self_hosted(support_email)}}
{% endif %}
</p>
{% endblock %}

View File

@@ -0,0 +1,5 @@
{% if create_realm %}
{{ _("Create your Zulip organization") }}
{% else %}
{{ _("Activate your Zulip account") }}
{% endif %}

View File

@@ -0,0 +1,22 @@
{% if create_realm %}
{{ _("You have requested a new Zulip organization:") }}
* {% trans %}Organization URL: {{ organization_url }}{% endtrans %}
* {% trans %}Organization type: {{ organization_type }}{% endtrans %}
{% else %}
{{ _("You recently signed up for Zulip. Awesome!") }}
{% endif %}
{% if create_realm %}
{{ _("Click the button below to create the organization and register your account. You'll be able to update the information above if you like.") }}
{% else %}
{{ _("Click the link below to complete registration.") }}
{% endif %}
<{{ activate_url }}>
{% if corporate_enabled %}
{% trans %}Do you have questions or feedback to share? Contact us at {{ support_email }} — we'd love to help!{% endtrans %}
{% else %}
{% trans %}If you have any questions, please contact this Zulip server's administrators at {{ support_email }}.{% endtrans %}
{% endif %}

View File

@@ -0,0 +1,25 @@
{% extends "zerver/emails/email_base_marketing.html" %}
{% block illustration %}
<img src="{{ email_images_base_url }}/email_logo.png" alt=""/>
{% endblock %}
{% block content %}
{# Note: The below code is substituted by `manage.py send_custom_email` #}
{{ rendered_input }}
{% endblock %}
{% block manage_preferences %}
{% if remote_server_email %}
{% if released_version %}
<p>You are receiving this email because you opted into release notifications.</p>
{% else %}
<p>You are receiving this email to update you about important changes to Zulip's Terms of Service.</p>
<a href="{{ unsubscribe_link }}">Unsubscribe</a>
{% endif %}
{% elif unsubscribe_link %}
<p><a href="{{ realm_url }}/#settings/notifications">{{ _("Manage email preferences") }}</a> | <a href="{{ unsubscribe_link }}">{{ _("Unsubscribe from marketing emails") }}</a></p>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,19 @@
---
{% if remote_server_email %}
{% if released_version %}
You are receiving this email because you opted into release notifications.
{% else %}
You are receiving this email to update you about important changes to Zulip's Terms of Service.
Unsubscribe: {{ unsubscribe_link }}
{% endif %}
{% elif unsubscribe_link %}
{{ _("Manage email preferences") }}:
{{ realm_url }}/#settings/notifications
{{ _("Unsubscribe from marketing emails") }}:
{{ unsubscribe_link }}
{% endif %}

View File

@@ -0,0 +1,20 @@
{% extends "zerver/emails/email_base_default.html" %}
{% block illustration %}
<img src="{{ email_images_base_url }}/email_logo.png" alt=""/>
{% endblock %}
{% block content %}
{% trans %}
Your Zulip account on <a href="{{ realm_url }}">{{ realm_url }}</a> has been deactivated, and you will no longer be able to log in.
{% endtrans %}
<br/><br/>
{% if deactivation_notification_comment %}
{{ _("The administrators provided the following comment:") }}
<pre class="deactivated-user-text">{{ deactivation_notification_comment }}</pre>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1 @@
{% trans %}Notification of account deactivation on {{ realm_name }}{% endtrans %}

View File

@@ -0,0 +1,9 @@
{% trans %}
Your Zulip account on {{ realm_url }} has been deactivated, and you will no longer be able to log in.
{% endtrans %}
{% if deactivation_notification_comment %}
{{ _("The administrators provided the following comment:") }}
{{ deactivation_notification_comment }}
{% endif %}

View File

@@ -0,0 +1,23 @@
{% 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>Cloud or self-hosting?</b>: {{ type_of_hosting }}
<br />
<b>Message</b>: {{ message }}
<br />
{% endblock %}

View File

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

View File

@@ -0,0 +1,17 @@
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 }}
Cloud or self-hosting?: {{ type_of_hosting }}
Message: {{ message }}

View File

@@ -0,0 +1,58 @@
{% extends "zerver/emails/email_base_messages.html" %}
{% block content %}
{% if show_message_content %}
{% if hot_conversations %}
{% for convo in hot_conversations %}
<div class='messages'>
{% with recipient_block=convo.first_few_messages %}
<div class='hot_convo_recipient_block'>
<div class='hot_convo_recipient_header'>{{ recipient_block.header.html|safe }}</div>
<div class='hot_convo_message_content'>
{% for sender_block in recipient_block.senders %}
{% for message_block in sender_block.content %}
<div class='hot_convo_message_content_block'>
{{ message_block.html|safe }}
</div>
{% endfor %}
{% endfor %}
</div>
</div>
{% if convo.count > 0 %}<p class="digest_paragraph">+ {{ convo.count }} more message{{ convo.count|pluralize }} by {{ convo.participants|display_list(4) }}.</p>{% endif %}
{% endwith %}
</div>
{% endfor %}
{% endif %}
{% if new_channels.html %}
<p class="digest_paragraph"><b>{% trans %}New channels{% endtrans %}</b></p>
<p class="digest_paragraph">{{ new_channels.html|display_list(1000)|safe }}.</p>
{% endif %}
{% else %}
<p class="digest_paragraph">
{% if new_messages_count > 0 and new_streams_count > 0 %}
{% trans %}You have {{ new_messages_count }} new messages, and there are {{ new_streams_count }} new channels in <a href="{{ realm_url }}">{{ realm_name }}</a>.{% endtrans %}
{% elif new_messages_count > 0 and new_streams_count == 0 %}
{% trans %}You have {{ new_messages_count }} new messages in <a href="{{ realm_url }}">{{ realm_name }}</a>.{% endtrans %}
{% else %}
{% trans %}There are {{ new_streams_count }} new channels in <a href="{{ realm_url }}">{{ realm_name }}</a>.{% endtrans %}
{% endif %}
</p>
<p class="digest_paragraph">
{% if message_content_disabled_by_realm %}
{% trans help_url=realm_url + "/help/hide-message-content-in-emails" %}This email does not include message content because your organization <a class="content_disabled_help_link" href="{{ help_url }}">hides message content</a> in email notifications.{% endtrans %}
{% elif message_content_disabled_by_user %}
{% trans help_url=realm_url + "/help/email-notifications#hide-message-content" %}This email does not include message content because you have chosen to <a class="content_disabled_help_link" href="{{ help_url }}">hide message content</a> in email notifications.{% endtrans %}
{% endif %}
</p>
{% endif %}
<p class="digest_paragraph">{% trans %}<a href="{{ realm_url }}">Log in</a> to Zulip to catch up.{% endtrans %}</p>
{% endblock %}
{% block manage_preferences %}
<p class="digest_paragraph">
<a href="{{ realm_url }}/#settings/notifications">{% trans %}Manage email preferences{% endtrans %}</a> |
<a href="{{ unsubscribe_link }}">{% trans %}Unsubscribe from digest emails{% endtrans %}</a>
</p>
{% endblock %}

View File

@@ -0,0 +1 @@
{% trans %}Zulip digest for {{ realm_name }}{% endtrans %}

View File

@@ -0,0 +1,41 @@
{% if show_message_content %}
{% if hot_conversations %}
{% for convo in hot_conversations %}{% with recipient_block=convo.first_few_messages %}{{ recipient_block.header.plain }}
{% for sender_block in recipient_block.senders %}
{% for message_block in sender_block.content %}{{ message_block.plain }}
{% endfor %}{% endfor %}
{% if convo.count > 0 %}+ {{ convo.count }} more message{{ convo.count|pluralize }} by {{ convo.participants|display_list(4) }}.{% endif %}{% endwith %}{% endfor %}{% endif %}
{% if new_channels.plain %}** {% trans %}New channels{% endtrans %} **
{{ new_channels.plain|display_list(1000) }}.
{% endif %}
{% else %}
{% if new_messages_count > 0 and new_streams_count > 0 %}
{% trans %}You have {{ new_messages_count }} new messages, and there are {{ new_streams_count }} new channels in {{ realm_name }}.{% endtrans %}
{% elif new_messages_count > 0 and new_streams_count == 0 %}
{% trans %}You have {{ new_messages_count }} new messages in {{ realm_name }}.{% endtrans %}
{% else %}
{% trans %}There are {{ new_streams_count }} new channels in {{ realm_name }}.{% endtrans %}
{% endif %}
{% if message_content_disabled_by_realm %}
{% trans hide_content_url=realm_url + "/help/hide-message-content-in-emails" %}
This email does not include message content because your organization hides message content in email notifications. See {{ hide_content_url }} for more details.
{% endtrans %}
{% elif message_content_disabled_by_user %}
{% trans help_url=realm_url + "/help/email-notifications#hide-message-content" %}
This email does not include message content because you have chosen to hide message content in email notifications. See {{ help_url }} for more details.
{% endtrans %}
{% endif %}
{% endif %}
{% trans organization_url=realm_url %}Log in to Zulip to catch up: {{ organization_url }}.{% endtrans %}
--
{% trans %}Manage email preferences:{% endtrans %}
{{ realm_url }}/#settings/notifications
{% trans %}Unsubscribe from digest emails:{% endtrans %}
{{ unsubscribe_link }}

View File

@@ -0,0 +1,358 @@
/* stylelint-disable color-no-hex, media-feature-range-notation */
/* Hex color codes are used instead of our standard of hsl colors,
because hex color codes are rendered by all email clients
consistently; HSL colors aren't supported by Hotmail. */
.illustration img,
img.bottom-illustration {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
vertical-align: bottom;
}
body.default-email-font-settings {
font-family: sans-serif;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
/* These .layout tables are used to create sections within the email;
see for example: https://templates.mailchimp.com/development/html/
*/
table.layout {
border-collapse: separate;
mso-table-lspace: 0;
mso-table-rspace: 0;
width: 100%;
}
table.layout > tbody > tr > td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* After email clients strip the actual body tag out of the email, the
.body element will be the equivalent of our outer element. */
.body {
width: 100%;
background-color: #f5f9f8;
}
.container {
display: block;
margin: 0 auto !important;
max-width: 500px;
padding: 10px;
}
/* This class is used to ensure that the images' width
does not exceed the actual email layout width. */
img.responsive-width {
max-width: 100%;
}
/* Our newsletters/marketing emails use a wider content width, to
support more complex content with text to the side of images. */
.container.wide-container {
max-width: 700px;
}
/* Mystery: .container contains .content, but the max-widths for this
element are 80px wider than those for .container. */
.content {
box-sizing: border-box;
display: block;
margin: 20px auto 0;
max-width: 580px;
padding: 10px;
}
.content.wide-content {
max-width: 780px;
}
/*
The main content region for the email; excludes the preheader and footer.
*/
.main {
background-color: #fff;
border-radius: 3px;
width: 100%;
}
/* Right/left padding to keep content away from edges of email client winder. */
.wrapper {
box-sizing: border-box;
padding: 0 20px 20px;
}
/* Footer section, containing unsubscribe links and the like. */
.footer {
clear: both;
padding-top: 10px;
text-align: center;
width: 100%;
margin-top: 20px;
}
/*
Apple mail and other popular email clients will convert the physical
address into a link, so we set link color on it.
*/
.footer-content-block,
.physical-address {
color: #5f5ec7;
font-size: 12px;
text-align: center;
}
/*
Styles for the content section of Zulip newsletters and other custom emails.
*/
.custom-email-content h1 {
font-size: 1.6em;
margin-top: 25px;
margin-bottom: 5px;
}
.content ul,
.content ol {
/* Override excessive indentation seen in Gmail. */
padding-left: 5px;
}
.body p,
p.digest_paragraph,
.content ul,
.content ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 10px 0;
}
.messages p.digest_paragraph {
line-height: normal;
margin: 4px 0 0;
}
.body p li,
.content ul li,
.content ol li {
list-style-position: outside;
margin-left: 15px;
}
/* Link color styling carefully tuned to not apply to user content
inside missed-message emails. */
.body a,
.digest_paragraph a,
.sponsorship_request_link,
.support_request_link,
.email-preferences a,
.missed_message.no-content-explanation a {
color: #5f5ec7;
text-decoration: underline;
}
.body a:hover,
.digest_paragraph a:hover,
.sponsorship_request_link:hover,
.support_request_link:hover,
.email-preferences a:hover,
.missed_message.no-content-explanation a:hover {
color: #434388 !important;
}
.body .button {
display: block;
padding: 10px 0;
margin: 20px auto;
width: 200px;
color: #5f5ec7;
border: 2px solid #5f5ec7;
background-color: #fff;
border-radius: 4px;
font-size: 16px;
outline: none;
font-family: sans-serif;
text-decoration: none;
text-align: center;
text-shadow: none;
}
.body a.button:hover {
background-color: #5f5ec7;
color: #fff;
text-decoration: none;
}
/* The preheader is an invisible region that is used to control what
email clients display as the textual preview of the email's content
in inbox views. */
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
mso-hide: all;
visibility: hidden;
width: 0;
}
/* Illustrations appear over the top of the boundary between the
blank space at the top of the email and the content box; for
that reason they need a high z-index. */
.illustration {
pointer-events: none;
cursor: default !important;
z-index: 100;
}
/* Styling for empty topic placeholders. */
.empty-topic-display {
font-style: italic;
}
/* CSS for digest email content. */
.messages {
width: 600px;
font-size: 12px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
overflow-y: auto;
margin-bottom: 12px;
}
.hot_convo_recipient_block {
border: 1px solid #000;
}
.hot_convo_recipient_header {
background-color: #9ec9ff;
border-bottom: 1px solid #000;
font-weight: bold;
padding: 2px;
}
.hot_convo_message_content {
margin-left: 1px;
margin-right: 2px;
}
.hot_convo_message_content_block {
padding-left: 6px;
font-weight: normal;
}
/* Text and link colors for missed-message emails. */
.email-preferences {
color: #666;
}
.email-preferences a {
color: #15c;
}
.content_disabled_help_link {
color: #15c;
}
/* Quoted block for text written by an organization administrator to
explain to the end user why their account got deactivated. */
.deactivated-user-text {
padding: 0 0 0 15px;
margin: 0 0 20px;
border-left: 5px solid #eee;
white-space: pre-line;
font-family: sans-serif;
font-size: 14px;
}
@media only screen and (max-width: 620px) {
table[class="body"] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class="body"] p,
table[class="body"] ul,
table[class="body"] ol,
table[class="body"] td,
table[class="body"] span,
table[class="body"] a {
font-size: 16px !important;
}
table[class="body"] .wrapper {
padding: 0 10px 10px;
}
table[class="body"] .content {
padding: 0 !important;
}
table[class="body"] .container {
padding: 0 !important;
width: 100% !important;
}
table[class="body"] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
}
@media all {
/* See https://templates.mailchimp.com/development/css/client-specific-styles/;
ExternalClass is something Microsoft Outlook adds to emails. */
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
/* iOS converts physical addresses in emails to links automatically,
so this CSS has an effect on iOS even though we don't actually
have a link inside the .physical-address element. */
.physical-address a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
}
/* Mechanism for images alongside content, mainly for use in newsletters. */
.float-right-image {
float: right;
}
/* The 450px cutoff was determined by testing in Gmail as a point
where an image looks good in either state. Logically it makes sense
since then the text still has the majority of the space in the
side-by-side view. */
@media only screen and (min-width: 450px) {
.float-right-image {
max-width: 200px;
}
}

View File

@@ -0,0 +1,53 @@
{% import 'zerver/emails/macros.html' as macros %}
{% import 'zerver/emails/email.css' as css_styles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width" />
<meta charset="UTF-8" />
<title>Zulip</title>
<style>{{css_styles}}</style>
</head>
<body class="default-email-font-settings">
<table border="0" cellpadding="0" cellspacing="0" class="body layout">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<a href="#" class="illustration">
{% block illustration %}{% endblock %}
</a>
<span class="preheader">
{% block preheader %}{% endblock %}
</span>
<table class="main layout">
<tr>
<td class="wrapper">
<table border="0" cellpadding="0" cellspacing="0" class="layout">
<tr>
<td>
{% block content %}{% endblock %}
</td>
</tr>
</table>
<img class="bottom-illustration" src="{{ email_images_base_url }}/footer.png" alt="{{ _('Swimming fish') }}"/>
</td>
</tr>
</table>
<div class="footer">
<table border="0" cellpadding="0" cellspacing="0" class="layout">
<tr>
<td class="footer-content-block">
<span class="physical-address">{{physical_address}}</span>
{% block manage_preferences %}{% endblock %}
</td>
</tr>
</table>
</div>
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@@ -0,0 +1,53 @@
{% import 'zerver/emails/macros.html' as macros %}
{% import 'zerver/emails/email.css' as css_styles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width" />
<meta charset="UTF-8" />
<title>Zulip</title>
<style>{{css_styles}}</style>
</head>
<body class="default-email-font-settings">
<table border="0" cellpadding="0" cellspacing="0" class="body layout">
<tr>
<td>&nbsp;</td>
<td class="container wide-container">
<div class="content wide-content">
<a href="#" class="illustration">
{% block illustration %}{% endblock %}
</a>
<span class="preheader">
{% block preheader %}{% endblock %}
</span>
<table class="main layout">
<tr>
<td class="wrapper">
<table border="0" cellpadding="0" cellspacing="0" class="layout">
<tr>
<td class="custom-email-content">
{% block content %}{% endblock %}
</td>
</tr>
</table>
<img src="{{ email_images_base_url }}/footer.png" alt="{{ _('Swimming fish') }}"/>
</td>
</tr>
</table>
<div class="footer">
<table border="0" cellpadding="0" cellspacing="0" class="layout">
<tr>
<td class="footer-content-block">
<span class="physical-address">{{physical_address}}</span>
{% block manage_preferences %}{% endblock %}
</td>
</tr>
</table>
</div>
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@@ -0,0 +1,30 @@
{% import 'zerver/emails/email.css' as css_styles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Zulip</title>
<style>{{css_styles}}</style>
</head>
<body>
{% if has_preheader %}
<span style="display:none !important;
visibility:hidden;
color:transparent;
mso-hide:all;
font-size:1px;
color:hsl(0, 0%, 100%);
line-height:1px;
max-height:0px;
height:0px;
max-width:0px;
width:0px;
opacity:0;
overflow:hidden;">
{% block preheader %}{% endblock %}
</span>
{% endif %}
{% block content %}{% endblock %}
{% block manage_preferences %}{% endblock %}
</body>
</html>

View File

@@ -0,0 +1,7 @@
{% extends "zerver/emails/email_base_messages.html" %}
{% block content %}
{{ message }}
{% endblock %}

View File

@@ -0,0 +1 @@
Error processing paid customer invoice

View File

@@ -0,0 +1 @@
{{ message }}

View File

@@ -0,0 +1,41 @@
{% extends "zerver/emails/email_base_default.html" %}
{% block illustration %}
<img src="{{ email_images_base_url }}/email_logo.png" alt=""/>
{% endblock %}
{% block content %}
{% if account_found %}
<p>{{ _("Thanks for your request!") }}</p>
{% if corporate_enabled %}
<p>{% trans %}Your email address {{ email }} has accounts with the following Zulip Cloud organizations:{% endtrans %}</p>
{% else %}
<p>{% trans %}Your email address {{ email }} has accounts with the following Zulip organizations hosted by {{ external_host }}:{% endtrans %}</p>
{% endif %}
<ul>
{% for realm_data in realms %}
<li><a href="{{ realm_data.url }}">{{ realm_data.name }} ({{ realm_data.host }})</a></li>
{% endfor %}
</ul>
<p>
{% trans %}If you have trouble logging in, you can <a href="{{ help_reset_password_link }}">reset your password</a>.{% endtrans %}
</p>
{% else %}
<p>
{{ _("You have requested a list of Zulip accounts for this email address.") }}
{% if corporate_enabled %}
{{ _("Unfortunately, no Zulip Cloud accounts were found.") }}
{% else %}
{% trans%}Unfortunately, no accounts were found in Zulip organizations hosted by {{external_host}}.{% endtrans %}
{% endif %}
</p>
<p>
{% trans %}You can <a href = "{{ find_accounts_link }}" >check for accounts</a> with another email, or <a href ="{{ help_logging_in_link }}">try another way</a> to find your account.{% endtrans %}
{{ _("If you do not recognize this request, you can safely ignore this email.") }}
</p>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,5 @@
{% if account_found %}
{{ _("Your Zulip accounts") }}
{% else %}
{{ _("No Zulip accounts found") }}
{% endif %}

View File

@@ -0,0 +1,36 @@
{% if account_found %}
{{ _("Thanks for your request!") }}
{% if corporate_enabled %}
{% trans %}Your email address {{ email }} has accounts with the following Zulip Cloud organizations:{% endtrans %}
{% else %}
{% trans %}Your email address {{ email }} has accounts with the following Zulip organizations hosted by {{ external_host }}:{% endtrans %}
{% endif %}
{% for realm_data in realms %}
* {{ realm_data.name }}: {{ realm_data.url }}
{% endfor %}
{% trans %}If you have trouble logging in, you can reset your password.{% endtrans %}
{{ help_reset_password_link }}
{% else %}
{% if corporate_enabled %}
{{ _("You have requested a list of Zulip accounts for this email address.") }} {{ _("Unfortunately, no Zulip Cloud accounts were found.") }}
{% trans %}You can check for accounts with another email ({{ find_accounts_link }}), or try another way to find your account ({{ help_logging_in_link }}).{% endtrans %}
{{ _("If you do not recognize this request, you can safely ignore this email.") }}
{% else %}
{{ _("You have requested a list of Zulip accounts for this email address.") }} {% trans%}Unfortunately, no accounts were found in Zulip organizations hosted by {{external_host}}.{% endtrans %}
{% trans %}You can check for accounts with another email ({{ find_accounts_link }}), or try another way to find your account ({{ help_logging_in_link }}).{% endtrans %}
{{ _("If you do not recognize this request, you can safely ignore this email.") }}
{% endif %}
{% endif %}

View File

@@ -0,0 +1,28 @@
{% extends "zerver/emails/email_base_default.html" %}
{% block content %}
<p>Internal billing notice for {{ billing_entity }}.</p>
{% if notice_reason == "fixed_price_plan_ends_soon" %}
<p>Reminder to re-evaluate the pricing and configure a new fixed-price plan accordingly.</p>
{% elif notice_reason == "stale_audit_log_data" %}
{% if fixed_price_plan %}
<p>Unable to verify current licenses in use, but invoicing not delayed because customer has a fixed-price plan.</p>
{% else %}
<p>Unable to verify current licenses in use, which delays invoicing for this customer.</p>
{% endif %}
<b>Last data upload</b>: {{ last_audit_log_update }}
{% elif notice_reason == "locally_deleted_realm_on_paid_plan" %}
<p>Investigate why remote realm is marked as locally deleted when it's on a paid plan.</p>
{% elif notice_reason == "license_discrepancy" %}
<p>Discrepancy in licenses when upgraded to current plan.</p>
<b>Licenses paid for</b>: {{ paid_licenses }}.
<b>Reported licenses in use</b>: {{ current_licenses }}.
{% endif %}
<br /><br />
<b>Support URL</b>: <a href="{{ support_url }}">{{ support_url }}</a>
{% endblock %}

View File

@@ -0,0 +1,9 @@
{% if notice_reason == "fixed_price_plan_ends_soon" %}
Fixed-price plan for {{ billing_entity }} ends on {{ end_date }}
{% elif notice_reason == "stale_audit_log_data" %}
Stale audit log data for {{ billing_entity }}'s plan
{% elif notice_reason == "locally_deleted_realm_on_paid_plan" %}
{{ billing_entity }} on paid plan marked as locally deleted
{% elif notice_reason == "license_discrepancy" %}
Check initial licenses invoiced for {{ billing_entity }}
{% endif %}

View File

@@ -0,0 +1,24 @@
Internal billing notice for {{ billing_entity }}.
{% if notice_reason == "fixed_price_plan_ends_soon" %}
Reminder to re-evaluate the pricing and configure a new fixed-price plan accordingly.
{% elif notice_reason == "stale_audit_log_data" %}
{% if fixed_price_plan %}
Unable to verify current licenses in use, but invoicing not delayed because customer has a fixed-price plan.
Last data upload: {{ last_audit_log_update }}
{% else %}
Unable to verify current licenses in use, which delays invoicing for this customer.
Last data upload: {{ last_audit_log_update }}
{% endif %}
{% elif notice_reason == "locally_deleted_realm_on_paid_plan" %}
Investigate why remote realm is marked as locally deleted when it's on a paid plan.
{% elif notice_reason == "license_discrepancy" %}
Discrepancy in licenses when upgraded to current plan.
Licenses paid for: {{ paid_licenses }}.
Reported licenses in use: {{ current_licenses }}.
{% endif %}
Support URL: {{ support_url }}

View File

@@ -0,0 +1,25 @@
{% extends "zerver/emails/email_base_default.html" %}
{% block illustration %}
<img src="{{ email_images_base_url }}/registration_confirmation.png" alt=""/>
{% endblock %}
{% block content %}
<p>{{ _("Hi there,") }}</p>
<p>
{% trans referrer_name=macros.referrer_email_tag(referrer_email, referrer_full_name) %}{{ referrer_name }} wants you to join them on Zulip &mdash; the team communication tool designed for productivity.{% endtrans %}
</p>
<p>
{{ _("To get started, click the button below.") }}
<a class="button" href="{{ activate_url }}">{{ _("Complete registration") }}</a>
</p>
<p>
{% if corporate_enabled %}
{{macros.contact_us_zulip_cloud(support_email)}}
{% else %}
{{macros.contact_us_self_hosted(support_email)}}
{% endif %}
</p>
{% endblock %}

View File

@@ -0,0 +1 @@
{% trans %}{{referrer_full_name}} has invited you to join {{ referrer_realm_name }}{% endtrans %}

View File

@@ -0,0 +1,12 @@
{{ _("Hi there,") }}
{% trans %}{{ referrer_full_name }} ({{ referrer_email }}) wants you to join them on Zulip -- the team communication tool designed for productivity.{% endtrans %}
{{ _("To get started, click the link below.") }}
<{{ activate_url }}>
{% if corporate_enabled %}
{% trans %}Do you have questions or feedback to share? Contact us at {{ support_email }} — we'd love to help!{% endtrans %}
{% else %}
{% trans %}If you have any questions, please contact this Zulip server's administrators at {{ support_email }}.{% endtrans %}
{% endif %}

View File

@@ -0,0 +1,27 @@
{% extends "zerver/emails/email_base_default.html" %}
{% block illustration %}
<img src="{{ email_images_base_url }}/invitation_reminder.png" alt=""/>
{% endblock %}
{% block content %}
<p>{{ _("Hi again,") }}</p>
<p>{% trans referrer_name=macros.referrer_email_tag(referrer_email, referrer_name) %}This is a friendly reminder that {{ referrer_name }} wants you to join them on Zulip &mdash; the team communication tool designed for productivity.{% endtrans %}</p>
<p>
{{ _("To get started, click the button below.") }}
<a class="button" href="{{ activate_url }}">{{ _("Complete registration") }}</a>
</p>
<p>
{{ _("This is the last reminder you'll receive for this invitation.") }}
</p>
<p>
{% trans referrer_name=macros.email_tag(referrer_email, referrer_name) %}
This invitation expires in two days. If the invitation expires,
you'll need to ask {{ referrer_name }} for another one.
{% endtrans %}
</p>
{% endblock %}

View File

@@ -0,0 +1 @@
{% trans %}Reminder: Join {{referrer_name}} at {{ referrer_realm_name }}{% endtrans %}

View File

@@ -0,0 +1,10 @@
{{ _("Hi again,") }}
{% trans %}This is a friendly reminder that {{ referrer_name }} ({{ referrer_email }}) wants you to join them on Zulip -- the team communication tool designed for productivity.{% endtrans %}
{{ _("To get started, click the link below.") }}
<{{ activate_url }}>
{{ _("This is the last reminder you'll receive for this invitation.") }}
{% trans %}This invitation expires in two days. If the invitation expires, you'll need to ask {{ referrer_name }} for another one.{% endtrans %}

View File

@@ -0,0 +1,19 @@
{% macro email_tag(email, text) -%}
<a href="mailto:{{ email }}">{{ text | default(email) }}</a>
{%- endmacro %}
{% macro referrer_email_tag(referrer_email, referrer_name) -%}
<a href="mailto:{{ referrer_email }}">{{ referrer_name }} ({{ referrer_email }})</a>
{%- endmacro %}
{% macro link_tag(url, text) -%}
<a href="{{ url }}">{{ text | default(url) }}</a>
{%- endmacro %}
{% macro contact_us_self_hosted(email) -%}
{% trans %}If you have any questions, please contact this Zulip server's administrators at <a href="mailto:{{ email }}">{{ email }}</a>.{% endtrans %}
{%- endmacro %}
{% macro contact_us_zulip_cloud(email) -%}
{% trans %}Do you have questions or feedback to share? <a href="mailto:{{ email }}">Contact us</a> — we'd love to help!{% endtrans %}
{%- endmacro %}

View File

@@ -0,0 +1,58 @@
{% extends "zerver/emails/email_base_messages.html" %}
{% block content %}
{% if show_message_content %}
{% with recipient_block=messages %}
{% for sender_block in recipient_block.senders %}
<div class="missed_message">
{% for message_block in sender_block.content %}
{{ message_block.html|safe }}
{% endfor %}
</div>
{% endfor %}
{% endwith %}
{% else %}
<div class="missed_message no-content-explanation">
{% if message_content_disabled_by_realm %}
{% trans help_url=realm_url + "/help/hide-message-content-in-emails" %}This email does not include message content because your organization <a class="content_disabled_help_link" href="{{ help_url }}">hides message content</a> in email notifications.{% endtrans %}
{% elif message_content_disabled_by_user %}
{% trans help_url=realm_url + "/help/email-notifications#hide-message-content" %}This email does not include message content because you have chosen to <a class="content_disabled_help_link" href="{{ help_url }}">hide message content</a> in email notifications.{% endtrans %}
{% endif %}
</div>
{% endif %}
{% endblock %}
{% block manage_preferences %}
<div class="email-preferences">
&mdash;<br />
{% if personal_mentioned %}
{% trans %}You are receiving this because you were personally mentioned.{% endtrans %}<br />
{% elif mentioned_user_group_name %}
{% trans %}You are receiving this because @{{ mentioned_user_group_name }} was mentioned.{% endtrans %}<br />
{% elif topic_wildcard_mentioned_in_followed_topic %}
{% trans %}You are receiving this because all topic participants were mentioned in #{{ channel_name }} > {{ topic_name }}.{% endtrans %}<br />
{% elif stream_wildcard_mentioned_in_followed_topic %}
{% trans %}You are receiving this because you have wildcard mention notifications enabled for topics you follow.{% endtrans %}<br />
{% elif topic_wildcard_mentioned %}
{% trans %}You are receiving this because all topic participants were mentioned in #{{ channel_name }} > {{ topic_name }}.{% endtrans %}<br />
{% elif stream_wildcard_mentioned %}
{% trans %}You are receiving this because everyone was mentioned in #{{ channel_name }}.{% endtrans %}<br />
{% elif followed_topic_email_notify %}
{% trans %}You are receiving this because you have email notifications enabled for topics you follow.{% endtrans %}<br />
{% elif stream_email_notify %}
{% trans %}You are receiving this because you have email notifications enabled for #{{ channel_name }}.{% endtrans %}<br />
{% endif %}
{% if reply_to_zulip %}
{% trans notif_url=realm_url + "/#settings/notifications" %}Reply to this email directly, <a href="{{ narrow_url }}">view it in {{ realm_name }} Zulip</a>, or <a href="{{ notif_url }}">manage email preferences</a>.{% endtrans %}
{% elif not show_message_content %}
{% trans notif_url=realm_url + "/#settings/notifications" %}<a href="{{ narrow_url }}">View or reply in {{ realm_name }} Zulip</a>, or <a href="{{ notif_url }}">manage email preferences</a>.{% endtrans %} <br />
{% else %}
{% trans notif_url=realm_url + "/#settings/notifications" %}<a href="{{ narrow_url }}">Reply in {{ realm_name }} Zulip</a>, or <a href="{{ notif_url }}">manage email preferences</a>.{% endtrans %} <br />
<br />
{% trans url="https://zulip.readthedocs.io/en/latest/production/email-gateway.html" %}
Do not reply to this email. This Zulip server is not configured to accept incoming emails (<a href="{{ url }}">help</a>).
{% endtrans %}
{% endif %}
</div>
{% endblock %}

View File

@@ -0,0 +1,20 @@
{% if show_message_content %}
{% if group_pm %} {% trans %}Group DMs with {{ direct_message_group_display_name }}{% endtrans %}
{% elif private_message %} {% trans %}DMs with {{ sender_str }}{% endtrans %}
{% elif stream_email_notify or mention or followed_topic_email_notify %}
{#
Some email clients, like Gmail Web (as of 2022), will auto-thread
emails that share a subject and recipients, but will disregard
[Bracketed Prefixes] in the style of old-school mailing lists. We take
advantage of this to retain thread continuity in email notifications
even after a topic is resolved.
#}
{% if topic_resolved %}{% trans %}[resolved] #{{ channel_name }} > {{ topic_name }}{% endtrans %}
{% else %}#{{ channel_name }} > {{ topic_name }}
{% endif %}
{% endif %}
{% else %}
{% trans %}New messages{% endtrans %}
{% endif %}
{% if include_realm_name_in_missedmessage_emails_subject %} [{{ realm_str }}]
{% endif %}

View File

@@ -0,0 +1,62 @@
{% if show_message_content %}
{% with recipient_block=messages %}
{% for sender_block in recipient_block.senders %}
{% for message_block in sender_block.content %}
{{ message_block.plain }}
{% endfor %}
{% endfor %}
{% endwith %}
{% else %}
{% if message_content_disabled_by_realm %}
{% trans hide_content_url=realm_url + "/help/hide-message-content-in-emails" %}
This email does not include message content because your organization hides message content in email notifications. See {{ hide_content_url }} for more details.
{% endtrans %}
{% elif message_content_disabled_by_user %}
{% trans help_url=realm_url + "/help/email-notifications#hide-message-content" %}
This email does not include message content because you have chosen to hide message content in email notifications. See {{ help_url }} for more details.
{% endtrans %}
{% endif %}
{% endif %}
--
{% if personal_mentioned %}
{% trans %}You are receiving this because you were personally mentioned.{% endtrans %}
{% elif mentioned_user_group_name %}
{% trans %}You are receiving this because @{{ mentioned_user_group_name }} was mentioned.{% endtrans %}
{% elif topic_wildcard_mentioned_in_followed_topic %}
{% trans %}You are receiving this because all topic participants were mentioned in #{{ channel_name }} > {{ topic_name }}.{% endtrans %}
{% elif stream_wildcard_mentioned_in_followed_topic %}
{% trans %}You are receiving this because you have wildcard mention notifications enabled for topics you follow.{% endtrans %}
{% elif topic_wildcard_mentioned %}
{% trans %}You are receiving this because all topic participants were mentioned in #{{ channel_name }} > {{ topic_name }}.{% endtrans %}
{% elif stream_wildcard_mentioned %}
{% trans %}You are receiving this because everyone was mentioned in #{{ channel_name }}.{% endtrans %}
{% elif followed_topic_email_notify %}
{% trans %}You are receiving this because you have email notifications enabled for topics you follow.{% endtrans %}
{% elif stream_email_notify %}
{% trans %}You are receiving this because you have email notifications enabled for #{{ channel_name }}.{% endtrans %}
{% endif %}
{% if reply_to_zulip %}
{% trans %}Reply to this email directly, or view it in {{ realm_name }} Zulip:{% endtrans %}
{{ narrow_url }}
{% elif not show_message_content %}
{% trans %}View or reply in {{ realm_name }} Zulip:{% endtrans %}
{{ narrow_url }}
{% else %}
{% trans %}Reply in {{ realm_name }} Zulip:{% endtrans %}
{{ narrow_url }}
{% trans %}
Do not reply to this email. This Zulip server is not configured to accept
incoming emails. Help:
{% endtrans %}
https://zulip.readthedocs.io/en/latest/production/email-gateway.html
{% endif %}
{% trans %}Manage email preferences:{% endtrans %}
{{ realm_url }}/#settings/notifications

View File

@@ -0,0 +1,16 @@
{% extends "zerver/emails/email_base_default.html" %}
{% block illustration %}
<img src="{{ email_images_base_url }}/email_logo.png" alt=""/>
{% endblock %}
{% block content %}
<p>{{ _("Hi,") }}</p>
<p>
{% trans new_email=macros.email_tag(new_email), support_email=macros.email_tag(support_email) %}The email associated with your Zulip account was recently changed to {{ new_email }}. If you did not request this change, please contact us immediately at {{ support_email }}.{% endtrans %}
</p>
<p>
{{ _("Best,") }}<br />
{{ _("Team Zulip") }}
</p>
{% endblock %}

View File

@@ -0,0 +1 @@
{% trans %}Zulip email changed for {{ realm_name }}{% endtrans %}

Some files were not shown because too many files have changed in this diff Show More