Compare commits

...

13 Commits

Author SHA1 Message Date
Tim Abbott
29b3dd0852 Release Zulip Server 2.0.1. 2019-03-04 17:39:57 -08:00
Tim Abbott
0ffc42083e i18n: Update translations from Transifex. 2019-03-04 17:28:30 -08:00
Tim Abbott
019e5a17f0 docs: Explain options for preventing changes during export.
This makes it a bit clearer that one doesn't need to deactivate a
realm just to export data.
2019-03-04 16:22:18 -08:00
Harshit Bansal
177673c84e portico: Refresh deactivated realm notice page every 60 seconds.
This helps avoid users being confused if a realm was temporarily
deactivated as part of getting a clean backup.

Fixes: #11757.
2019-03-04 16:22:10 -08:00
Harshit Bansal
f6c1a31988 auth: Remove invalid_subdomain restriction from LDAP backend.
Fixes: #11692.
2019-03-04 16:22:04 -08:00
Tim Abbott
870cd00f5f su_to_zulip: Fix detection of zulip user ID.
Apparently, while upgrade-zulip-from-git always ensures that zulip
deployment directories are owned by the Zulip user, unpack-zulip (aka
the tarball code path) has them owned by root.

The user ID detection logic in su_to_zulip's helper get_zulip_uid was
intended to support both development environments (where the user ID
might vary) and production environments.  For development
environments, the existing code is fine, but given this unpack-zulip
permissions issue, we need to have code to fallback to 'zulip' if the
detection logic detects the "zulip" user has having UID 0.
2019-03-04 16:21:53 -08:00
Aaron Raimist
7db599deaa docs: Fix Learn more about mentions link.
It seems like 1871d00bb2 renamed `/help/at-mention-a-user` to `/help/mention-a-user-or-group` but missed this link that shows up on the "You haven't been mentioned yet!" screen. Right now it leads to a "no such article page".
2019-03-04 11:12:56 -08:00
Tim Abbott
84d2be5e0c docs: Fix export/import manage.py instructions typos.
Fixes #11755.
2019-03-04 11:12:48 -08:00
Tim Abbott
d360833d7f nginx: Restructure how we manage uploaded file routes.
The overall goal of this change is to fix an issue where on Ubuntu
Trusty, we were accidentally overriding the configuration to serve
uploads from disk with the regular expressions for adding access
control headers.

However, while investigating this, it became clear that we could
considerably simplify the mental energy required to understand this
system by making the uploads-route file be unconditionally available
and included from `zulip-include/app` (which means the zulip_ops code
can share behavior here).

We also move the Access-Control-Allow-* headers to a separate include
file, to avoid duplicating it in 5 places.  Fixing this duplication
discovered a potential bug in the settings used for Tornado, where
DELETE was not allowed on a route that definitely expects DELETE.

Fixes #11758.
2019-03-04 11:12:44 -08:00
Tim Abbott
bc3db1701b realm_logo: Fix synchronization of realm night logo.
The night logo synchronization on the settings page was perfect, but
the actual display logic had a few problems:

* We were including the realm_logo in context_processors, even though
  it is only used in home.py.
* We used different variable names for the templating in navbar.html
  than anywhere else the codebase.

* The behavior that the night logo would default to the day logo if
  only one was uploaded was not correctly implemented for the navbar
  position, either in the synchronization for updates code or the
  logic in the navbar.html templates.
2019-03-04 11:12:36 -08:00
Rishi Gupta
e8aca7b723 help: Reorganize stream-permissions table. 2019-03-04 11:12:32 -08:00
Tim Abbott
7a72390710 copy: Fix extra space before > in copy-paste styling. 2019-03-04 11:12:11 -08:00
Boris Yankov
3ffe4ca3e5 user status: Make "unavailable" status circle grey.
After discussion, we decided that the red color is too distinct
and does not convey the idea of "almost offline".

This changes the new "unavailable" status circle's color from dark
red to grey, the same color used by the "offline" status circle.
2019-03-04 11:11:52 -08:00
31 changed files with 350 additions and 166 deletions

View File

@@ -52,7 +52,7 @@ author = 'The Zulip Team'
# The short X.Y version.
version = '2.0'
# The full version, including alpha/beta/rc tags.
release = '2.0.0'
release = '2.0.1'
# This allows us to insert a warning that appears only on an unreleased
# version, e.g. to say that something is likely to have changed.

View File

@@ -7,6 +7,19 @@ All notable changes to the Zulip server are documented in this file.
This section lists notable unreleased changes; it is generally updated
in bursts.
### 2.0.1 -- 2019-03-04
- Fixed handling of uploaded file routing on Ubuntu Trusty.
- Fixed buggy behavior of branding logos in night theme.
- Fixed handling of deployment directories being owned by root.
- The styling of "unavailable" status icons is now less prominent.
- The "deactivated realm" error page now auto-refreshes, to handle
realm reactivation.
- Updated documentation to avoid recommending realm deactivation as
a preferred approach to prepare for backups.
- Added support for using multiple organizations with same LDAP
backend configuration.
### 2.0.0 -- 2019-03-01
**Highlights:**

View File

@@ -31,19 +31,39 @@ process.
[backups]: ../production/maintain-secure-upgrade.html#backups
## Export your Zulip data
## Preventing changes during the export
For best results, you'll want to shut down access to the organization
you are exporting with `manage.py deactivate_realm` before exporting,
so that nobody can send new messages (etc.) while you're exporting
data. We include that in the instructions below.
before exporting, so that nobody can send new messages (etc.) while
you're exporting data. There are two ways to do this:
1. `supervisorctl stop all`, which stops the whole server. This is
preferred if you're not hosting multiple organizations, because it has
no side effects other than disabling the Zulip server for the
duration.
1. `manage.py deactivate_realm`, which deactivates the target
organization, logging out all active login sessions and preventing all
accounts in the from logging in or accessing the API. This is
preferred for environments like Zulip Cloud where you might want to
export a single organization without disrupting any other users, and
the intent is to move hosting of the organization (and forcing users
to re-login would be required as part of the hosting migrateion
anyway).
We include both options in the instructions below, commented out so
that neither runs (using the `# ` at the start of the lines). If
you'd like to use one of these options, remove the `# ` at the start
of the lines for the appropriate option.
## Export your Zulip data
Log in to a shell on your Zulip server as the `zulip` user. Run the
following commands:
```
cd /home/zulip/deployments/current
./manage deactivate_realm -r '' # Deactivates the organization
# ./manage.py deactivate_realm -r '' # Deactivates the organization
# supervisorctl stop all # Stops the Zulip server
./manage.py export -r '' # Exports the data
```
@@ -83,7 +103,8 @@ cd ~
tar -xf /path/to/export/file/zulip-export-zcmpxfm6.tar.gz
cd /home/zulip/deployments/current
./manage.py import '' ~/zulip-export-zcmpxfm6
./manage reactivate_realm -r '' # Reactivates the organization
# supervisorctl start all # Starts the Zulip server
# ./manage.py reactivate_realm -r '' # Reactivates the organization
```
This could take several minutes to run, depending on how much data you're
@@ -99,7 +120,7 @@ root domain. Replace the last two lines above with the following, after replacin
```
./manage.py import <subdomain> ~/zulip-export-zcmpxfm6
./manage reactivate_realm -r <subdomain> # Reactivates the organization
./manage.py reactivate_realm -r <subdomain> # Reactivates the organization
```
## Logging in

View File

@@ -0,0 +1,3 @@
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers Authorization;
add_header Access-Control-Allow-Methods 'GET, POST, DELETE, PUT, PATCH, HEAD';

View File

@@ -27,15 +27,9 @@ location ~ /json/events {
# Send longpoll requests to Tornado
location /api/v1/events {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers Authorization;
add_header Access-Control-Allow-Methods 'GET, POST';
include /etc/nginx/zulip-include/api_headers;
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers Authorization;
add_header Access-Control-Allow-Methods 'GET, POST';
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
@@ -60,15 +54,20 @@ location / {
uwsgi_pass django;
}
# Certain Django routes not under /api are shared between mobile and
# web and thus need API headers added. We don't collapse this with the
# above block for /events, because regular expressions take priority over
# paths in nginx's order-of-operations, and we don't want to override the
# tornado stuff.
location ~ ^/(user_uploads|avatar|thumbnail)/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers Authorization;
add_header Access-Control-Allow-Methods 'GET, POST, DELETE, PUT, PATCH, HEAD';
# These Django routes not under /api are shared between mobile and
# web, and thus need API headers added. We can't easily collapse
# these blocks with the /api block, because regular expressions take
# priority over paths in nginx's order-of-operations, and we don't
# want to override the tornado configuration for /api/v1/events. The
# last is handled via uploads-route.
location /thumbnail {
include /etc/nginx/zulip-include/api_headers;
include uwsgi_params;
uwsgi_pass django;
}
location /avatar {
include /etc/nginx/zulip-include/api_headers;
include uwsgi_params;
uwsgi_pass django;
@@ -76,12 +75,11 @@ location ~ ^/(user_uploads|avatar|thumbnail)/ {
# Send all API routes not covered above to Django via uWSGI
location /api/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers Authorization;
add_header Access-Control-Allow-Methods 'GET, POST, DELETE, PUT, PATCH, HEAD';
include /etc/nginx/zulip-include/api_headers;
include uwsgi_params;
uwsgi_pass django;
}
include /etc/nginx/zulip-include/uploads.route;
include /etc/nginx/zulip-include/app.d/*.conf;

View File

@@ -1,4 +1,10 @@
# This Django route not under /api is shared between mobile and web
# and thus needs API headers added, in addition to the configuration
# required to have it serve files directly.
location /user_uploads {
include /etc/nginx/zulip-include/api_headers;
add_header X-Content-Type-Options nosniff;
add_header Content-Security-Policy "default-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self'; object-src 'self'; plugin-types application/pdf;";
include /etc/nginx/zulip-include/uploads.types;

View File

@@ -5,3 +5,14 @@ location /serve_uploads {
include /etc/nginx/zulip-include/uploads.types;
alias /home/zulip/uploads/files;
}
# This Django route not under /api is shared between mobile and web
# and thus needs API headers added, in addition to the configuration
# required to have this URL be served by Django.
location /user_uploads {
include /etc/nginx/zulip-include/api_headers;
include uwsgi_params;
uwsgi_pass django;
}

View File

@@ -0,0 +1,10 @@
# This Django route not under /api is shared between mobile and web
# and thus needs API headers added, in addition to the configuration
# required to have this URL be served by Django.
location /user_uploads {
include /etc/nginx/zulip-include/api_headers;
include uwsgi_params;
uwsgi_pass django;
}

View File

@@ -41,6 +41,11 @@ class zulip::nginx {
'trusty' => 'puppet:///modules/zulip/nginx/zulip-include-maybe/uploads-route.direct',
default => 'puppet:///modules/zulip/nginx/zulip-include-maybe/uploads-route.internal',
}
$no_serve_uploads = zulipconf('application_server', 'no_serve_uploads', '')
if $no_serve_uploads != '' {
# If we're not serving uploads locally, set the appropriate API headers for it.
$uploads_route = 'puppet:///modules/zulip/nginx/zulip-include-maybe/uploads-route.noserve'
}
file { '/etc/nginx/zulip-include/uploads.route':
ensure => file,

View File

@@ -37,7 +37,4 @@ server {
include /etc/nginx/zulip-include/certbot;
include /etc/nginx/zulip-include/app;
<% if @no_serve_uploads == '' -%>
include /etc/nginx/zulip-include/uploads.route;
<% end -%>
}

View File

@@ -110,8 +110,15 @@ def subprocess_text_output(args):
# type: (Sequence[str]) -> str
return subprocess.check_output(args, universal_newlines=True).strip()
def get_zulip_uid() -> int:
return os.stat(get_deploy_root()).st_uid
def get_zulip_pwent() -> pwd.struct_passwd:
deploy_root_uid = os.stat(get_deploy_root()).st_uid
if deploy_root_uid != 0:
return pwd.getpwuid(deploy_root_uid)
# In the case that permissions got messed up and the deployment
# directory is unexpectedly owned by root, we fallback to the
# `zulip` user as that's the correct value in production.
return pwd.getpwnam("zulip")
def su_to_zulip(save_suid=False):
# type: (bool) -> None
@@ -120,7 +127,7 @@ def su_to_zulip(save_suid=False):
installation). It should never be run from the installer or other
production contexts before /home/zulip/deployments/current is
created."""
pwent = pwd.getpwuid(get_zulip_uid())
pwent = get_zulip_pwent()
os.setgid(pwent.pw_gid)
if save_suid:
os.setresuid(pwent.pw_uid, pwent.pw_uid, os.getuid())
@@ -422,7 +429,7 @@ def is_root() -> bool:
def assert_not_running_as_root() -> None:
script_name = os.path.abspath(sys.argv[0])
if is_root():
pwent = pwd.getpwuid(get_zulip_uid())
pwent = get_zulip_pwent()
msg = ("{shortname} should not be run as root. Use `su {user}` to switch to the 'zulip'\n"
"user before rerunning this, or use \n su {user} -c '{name} ...'\n"
"to switch users and run this as a single command.").format(

View File

@@ -75,7 +75,7 @@ var realm_logo = (function () {
$("#realm-settings-night-logo").attr("src", page_params.realm_night_logo_url);
}
if (page_params.night_mode) {
if (page_params.night_mode && page_params.realm_night_logo_source !== 'D') {
$("#realm-logo").attr("src", page_params.realm_night_logo_url);
} else {
$("#realm-logo").attr("src", page_params.realm_logo_url);

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-03-01 17:24+0000\n"
"POT-Creation-Date: 2019-03-05 01:24+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -591,7 +591,8 @@ msgstr ""
#: templates/zerver/app/home.html:138
msgid ""
"\n"
" Learn more about mentions <a href=\"/help/at-mention-a-user\">\n"
" Learn more about mentions <a href=\"/help/mention-a-user-or-group"
"\">\n"
" here</a>.\n"
" "
msgstr ""
@@ -1406,11 +1407,11 @@ msgstr ""
msgid "Create organization"
msgstr ""
#: templates/zerver/deactivated.html:9
#: templates/zerver/deactivated.html:15
msgid "Deactivated organization"
msgstr ""
#: templates/zerver/deactivated.html:14
#: templates/zerver/deactivated.html:20
#, python-format
msgid ""
"\n"
@@ -3245,7 +3246,7 @@ msgstr ""
msgid "Invalid type parameter"
msgstr ""
#: zerver/lib/events.py:742
#: zerver/lib/events.py:745
msgid "Could not allocate event queue"
msgstr ""
@@ -3842,7 +3843,7 @@ msgstr ""
msgid "This user is not registered; do so from a browser."
msgstr ""
#: zerver/views/auth.py:798 zerver/views/auth.py:889
#: zerver/views/auth.py:798 zerver/views/auth.py:887
msgid "Your username or password is incorrect."
msgstr ""
@@ -3854,7 +3855,7 @@ msgstr ""
msgid "Subdomain required"
msgstr ""
#: zerver/views/auth.py:897
#: zerver/views/auth.py:895
msgid "GOOGLE_CLIENT_ID is not configured"
msgstr ""

View File

@@ -10,8 +10,8 @@ msgstr ""
"Project-Id-Version: Zulip\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-02-14 00:07+0000\n"
"PO-Revision-Date: 2019-02-14 00:08+0000\n"
"Last-Translator: Tim Abbott <tabbott@kandralabs.com>\n"
"PO-Revision-Date: 2019-03-05 00:19+0000\n"
"Last-Translator: Andrea <andrea.soccal@elmospa.com>\n"
"Language-Team: Italian (http://www.transifex.com/zulip/zulip/language/it/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -226,7 +226,7 @@ msgstr ""
#: templates/corporate/upgrade.html:83
msgid "Most convenient"
msgstr ""
msgstr "Più conveniente"
#: templates/corporate/upgrade.html:89
msgid "Manual"
@@ -423,7 +423,7 @@ msgstr "Aggiungi videochiamata"
#: templates/zerver/app/compose.html:102
msgid "Write"
msgstr ""
msgstr "Scrivi"
#: templates/zerver/app/compose.html:103
msgid "Preview"
@@ -641,12 +641,12 @@ msgstr "Uno o più indirizzi email..."
#: templates/zerver/app/invite_user.html:20
msgid "or"
msgstr ""
msgstr "o"
#: templates/zerver/app/invite_user.html:20
#: templates/zerver/app/invite_user.html:26
msgid "Generate invite link"
msgstr ""
msgstr "Genera link di invito"
#: templates/zerver/app/invite_user.html:33
msgid "User(s) join as"
@@ -662,7 +662,7 @@ msgstr "Amministratori dell'organizzazione"
#: templates/zerver/app/invite_user.html:40
msgid "Guests"
msgstr ""
msgstr "Ospiti"
#: templates/zerver/app/invite_user.html:45
msgid "Streams they should join"
@@ -670,7 +670,7 @@ msgstr "Canali che dovrebbero seguire"
#: templates/zerver/app/invite_user.html:52
msgid "Inviting..."
msgstr ""
msgstr "Sto invitando..."
#: templates/zerver/app/invite_user.html:52
msgid "Invite"
@@ -1433,7 +1433,7 @@ msgstr "Utenti normali"
#: templates/zerver/emails/find_team.txt:1
#, python-format
msgid "Hi %(user_name)s,"
msgstr ""
msgstr "Ciao %(user_name)s,"
#: templates/zerver/emails/compiled/confirm_new_email.html:11
#: templates/zerver/emails/confirm_new_email.source.html:10
@@ -1443,7 +1443,7 @@ msgid ""
"We received a request to change the email address for the Zulip account on "
"%(realm_uri)s from %(old_email)s to %(new_email)s. To confirm this change, "
"please click below:"
msgstr ""
msgstr "Abbiamo ricevuto una richiesta di modifica dell'indirizzo email per l'account Zulip su %(realm_uri)s da %(old_email)s a %(new_email)s. Per confermare questa modifica, per favore clicca sul link di seguito: "
#: templates/zerver/emails/compiled/confirm_new_email.html:12
#: templates/zerver/emails/confirm_new_email.source.html:11
@@ -1535,7 +1535,7 @@ msgstr ""
#: templates/zerver/emails/followup_day1.source.html:14
#, python-format
msgid "You've joined the Zulip organization <b>%(realm_name)s</b>."
msgstr ""
msgstr "Sei entrato nell'organizzazione Zulip <b>%(realm_name)s</b>."
#: templates/zerver/emails/compiled/followup_day1.html:20
#: templates/zerver/emails/followup_day1.source.html:19
@@ -1617,7 +1617,7 @@ msgid ""
"decoration:underline\">GitHub</a>, or chat with us live on the <a "
"href=\"https://chat.zulip.org\" style=\"color:#46aa8f; text-"
"decoration:underline\">Zulip community server</a>!"
msgstr ""
msgstr "PS: Seguici su <a href=\"https://twitter.com/zulip\" style=\"color:#46aa8f; text-decoration:underline\">Twitter</a>, seguici su <a href=\"https://github.com/zulip/zulip\" style=\"color:#46aa8f; text-decoration:underline\">GitHUb</a>, o chatta con noi live su <a href=\"https://chat.zulip.org\" style=\"color:#46aa8f; text-decoration:underline\">Zulip community server</a>!"
#: templates/zerver/emails/compiled/followup_day2.html:9
#: templates/zerver/emails/followup_day2.source.html:8
@@ -1693,7 +1693,7 @@ msgstr ""
#: templates/zerver/emails/compiled/followup_day2.html:35
#: templates/zerver/emails/followup_day2.source.html:34
msgid "Unsubscribe from welcome emails"
msgstr ""
msgstr "Annulla l'iscrizione alle e-mail di benvenuto"
#: templates/zerver/emails/compiled/invitation.html:9
#: templates/zerver/emails/invitation.source.html:8
@@ -1767,7 +1767,7 @@ msgstr ""
msgid ""
"Organization: %(organization_url)s Time: %(login_time)s Email: "
"%(user_email)s"
msgstr ""
msgstr "ORganizzazione: %(organization_url)s Ora: %(login_time)s Email: %(user_email)s"
#: templates/zerver/emails/compiled/notify_new_login.html:13
#: templates/zerver/emails/notify_new_login.source.html:12
@@ -1831,7 +1831,7 @@ msgstr ""
#: templates/zerver/emails/notify_new_login.source.html:41
#: templates/zerver/emails/notify_new_login.txt:20
msgid "Zulip Security"
msgstr ""
msgstr "Sicurezza Zulip"
#: templates/zerver/emails/compiled/notify_new_login.html:48
#: templates/zerver/emails/notify_new_login.source.html:46
@@ -1845,7 +1845,7 @@ msgstr "Annulla l'iscrizione delle notifiche del login"
msgid ""
"Somebody (possibly you) requested a new password for the Zulip account "
"%(email)s on %(realm_uri)s."
msgstr ""
msgstr "Qualcuno (probabilmente tu) ha richiesto una nuova password per il tuo account Zulip %(email)sin %(realm_uri)s."
#: templates/zerver/emails/compiled/password_reset.html:14
#: templates/zerver/emails/password_reset.source.html:13
@@ -1855,7 +1855,7 @@ msgstr ""
#: templates/zerver/emails/compiled/password_reset.html:15
#: templates/zerver/emails/password_reset.source.html:14
msgid "Reset password"
msgstr ""
msgstr "Resetta la password"
#: templates/zerver/emails/compiled/password_reset.html:20
#, python-format
@@ -1871,7 +1871,7 @@ msgstr ""
#: templates/zerver/emails/password_reset.source.html:21
#: templates/zerver/emails/password_reset.txt:10
msgid "You do not have an account in that Zulip organization."
msgstr ""
msgstr "Non hai un account in quella organizzazione in Zulip."
#: templates/zerver/emails/compiled/password_reset.html:27
#: templates/zerver/emails/password_reset.source.html:26
@@ -1933,7 +1933,7 @@ msgstr ""
msgid ""
"If you did not request this change, please contact us immediately at <a "
"href=\"mailto:%(support_email)s\">%(support_email)s</a>."
msgstr ""
msgstr "Se non hai richiesto questo cambiamento, ti preghiamo di contattarci immediatamente a <a href=\"mailto:%(support_email)s\">%(support_email)s</a>."
#: templates/zerver/emails/confirm_new_email.subject.txt:1
msgid "Verify your new email address"
@@ -1981,7 +1981,7 @@ msgstr ""
msgid ""
"(you'll need these to sign in to the <a "
"href=\"https://zulipchat.com/apps\">mobile and desktop</a> apps)"
msgstr ""
msgstr "(ne avrai bisogno per registrati alla app <a href=\"https://zulipchat.com/apps\">mobile e desktop</a>)"
#: templates/zerver/emails/followup_day1.source.html:35
#, python-format
@@ -2010,22 +2010,22 @@ msgstr ""
#: templates/zerver/emails/followup_day1.subject.txt:2
#, python-format
msgid "%(realm_name)s on Zulip: Your new organization details"
msgstr ""
msgstr "%(realm_name)s in Zulip: I dettagli della tua nuova organizzazione"
#: templates/zerver/emails/followup_day1.subject.txt:4
#, python-format
msgid "%(realm_name)s on Zulip: Your new account details"
msgstr ""
msgstr "%(realm_name)sin Zulip: I dettagli del tuo nuovo account"
#: templates/zerver/emails/followup_day1.txt:4
#, python-format
msgid "You've created the new Zulip organization %(realm_name)s."
msgstr ""
msgstr "Hai creato la nuova organizzazione %(realm_name)sin Zulip. "
#: templates/zerver/emails/followup_day1.txt:6
#, python-format
msgid "You've joined the Zulip organization %(realm_name)s."
msgstr ""
msgstr "Sei entrato nell'organizzazione Zulip %(realm_name)s."
#: templates/zerver/emails/followup_day1.txt:21
msgid ""
@@ -2182,12 +2182,12 @@ msgstr ""
#: templates/zerver/emails/notify_new_login.source.html:16
#, python-format
msgid "Organization: <a href=\"%(realm_uri)s\" target=\"_blank\">%(realm_uri)s</a>"
msgstr ""
msgstr "Organizzazione: <a href=\"%(realm_uri)s\" target=\"_blank\">%(realm_uri)s</a>"
#: templates/zerver/emails/notify_new_login.source.html:19
#, python-format
msgid "Email: <a href=\"mailto:%(user_email)s\" target=\"_blank\">%(user_email)s</a>"
msgstr ""
msgstr "Email: <a href=\"mailto:%(user_email)s\" target=\"_blank\">%(user_email)s</a>"
#: templates/zerver/emails/notify_new_login.source.html:36
#, python-format
@@ -2201,12 +2201,12 @@ msgstr ""
#: templates/zerver/emails/notify_new_login.subject.txt:1
#, python-format
msgid "New login from %(device_browser)s on %(device_os)s"
msgstr ""
msgstr "Nuovo accesso da %(device_browser)s in %(device_os)s"
#: templates/zerver/emails/notify_new_login.txt:3
#, python-format
msgid "Organization: %(organization_url)s"
msgstr ""
msgstr "Organizzazione: %(organization_url)s"
#: templates/zerver/emails/notify_new_login.txt:5
#, python-format
@@ -3304,7 +3304,7 @@ msgstr "Ogni messaggio ha un argomento, Gli argomenti rendono le conversazioni a
#: zerver/lib/hotspots.py:26
msgid "Go to Settings to configure your notifications and display settings."
msgstr ""
msgstr "Vai a Impostazioni per configurare le notifiche e le impostazioni di visualizzazione."
#: zerver/lib/hotspots.py:30
msgid "Compose"
@@ -3470,7 +3470,7 @@ msgstr ""
#: zerver/lib/upload.py:120 zerver/lib/upload.py:135 zerver/lib/upload.py:187
msgid "Image size exceeds limit."
msgstr ""
msgstr "Le dimensioni dell'immagine superano il limite."
#: zerver/lib/upload.py:288
msgid "Upload would exceed your organization's upload quota."
@@ -4418,4 +4418,4 @@ msgstr ""
#: zilencer/views.py:160
msgid "Data is out of order."
msgstr ""
msgstr "I dati sono fuori servizio."

View File

@@ -80,7 +80,7 @@
"Are invitations required for joining the organization?": "E' richiesto un invito per entrare nell'organizzazione?",
"Are you sure you want to create stream '__stream_name__' and subscribe __count__ users to it?": "Sei sicuro di voler creare il canale '__stream_name__' e sottoscrivere __count__ utenti?",
"Are you sure you want to delete <b>__group_name__</b>?": "Sei sicuro di voler cancellare <b>__group_name__</b>?",
"Are you sure you want to delete all messages in <b>__topic_name__</b>?": "",
"Are you sure you want to delete all messages in <b>__topic_name__</b>?": "Sei sicuro di voler cancellare tutti i messaggi in <b>__topic_name__</b>?",
"Are you sure you want to do this?": "Sei sicuro di volerlo fare?",
"Are you sure you want to mention all <strong>__count__</strong> people in this stream?": "Sei sicuro di voler menzionare tutte le <strong>__count__</strong> persone in questo canale?",
"Are you sure you want to resend the invitation to <strong><span class=\"email\"></span></strong>?": "Sei sicuro di voler rispedire l'invito a <strong><span class=\"email\"></span></strong>?",
@@ -101,7 +101,7 @@
"By deactivating your account, you will be logged out immediately.": "Disattivando il tuo account, sarai scollegato immediatamente.",
"Cancel": "Cancella",
"Change": "Modifica",
"Change bot info and owner": "",
"Change bot info and owner": "Modifica le info sul bot e il proprietario",
"Change email": "Modifica email",
"Change full name": "Modifica il nome",
"Change later messages to this topic": "imposta a questo argomento i messaggi successivi",
@@ -156,12 +156,12 @@
"Deactivated users": "Utenti disattivati",
"Deactivation encountered an error. Please reload and try again.": "Errore durante la disattivazione: per favore ricarica e riprova.",
"Default language": "Lingua di default",
"Default settings for new users joining this organization.": "",
"Default settings for new users joining this organization.": "Impostazioni di default per i nuovi utenti che entrano in questa organizzazione.",
"Default streams": "Canali di default",
"Default user settings": "Impostazioni utente di default",
"Delete": "Cancella",
"Delete alert word": "Cancella parola allarme",
"Delete all messages in <b>__topic_name__</b>": "",
"Delete all messages in <b>__topic_name__</b>": "Cancella tutti i messaggi in <b>__topic_name__</b>",
"Delete avatar": "Cancella avatar",
"Delete bot": "Cancella bot",
"Delete draft": "Cancella bozza",
@@ -169,7 +169,7 @@
"Delete icon": "Cancella icona",
"Delete logo": "Cancella logo",
"Delete message": "Cancella messaggio",
"Delete messages": "",
"Delete messages": "Cancella messaggi",
"Delete stream": "Cancella canale",
"Delete topic": "Cancella argomento",
"Delete user group": "Cancella gruppo di utenti",
@@ -246,7 +246,7 @@
"Forgotten it?": "Dimenticato?",
"Formatting": "Sto formattando",
"Full name": "Nome",
"Generate invite link": "",
"Generate invite link": "Genera link di invito",
"Generate new API key": "Genera nuova chiave API",
"Generating link...": "Generazione del link...",
"Generic": "Generico",
@@ -254,7 +254,7 @@
"Go back": "Indietro",
"Got it!": "Capito!",
"Guest": "Ospite",
"Guests cannot edit custom emoji.": "",
"Guests cannot edit custom emoji.": "Gli ospiti non posso modificare le emoji custom.",
"High contrast mode": "Modalità ad alto conrasto",
"Hint": "Suggerimento",
"Hint (up to 80 characters)": "Suggerimento (fino a 80 caratteri)",
@@ -268,16 +268,16 @@
"Interface": "Interfaccia",
"Invalid slash command. Check if you are missing a space after the command.": "Comando slash invalido. Verifica se manca uno spazio dopo il comando",
"Invalid stream id": "Identificativo canale non valido",
"Invitation link: <a href=\"__link__\">__link__</a>": "",
"Invitation link: <a href=\"__link__\">__link__</a>": "Link di invito:<a href=\"__link__\">__link__</a>",
"Invitations": "Inviti",
"Invite": "Invita",
"Invite more users": "Invita altri utenti",
"Invited as": "",
"Invited as": "Invitato come",
"Invited as administrator": "Invitato come amministratore",
"Invited at": "Invitato a",
"Invited by": "Invitato da",
"Invites": "Invita",
"Inviting...": "",
"Inviting...": "Sto invitando...",
"It's been a while! Since you were last here, you received <b>__unread_count__</b> new messages.": "Manchi da un po'! Dalla tua ultima visita, hai ricevuto <b>__unread_count__</b> nuovi messaggi.",
"Joined": "Unito",
"Joining the organization": "Sto entrando nell'organizzazione",
@@ -397,7 +397,7 @@
"Organization settings": "Impostazione dell'organizzazione",
"Other notification settings": "Altre impostazioni delle notifiche",
"Other permissions": "Altri permessi",
"Other settings": "",
"Other settings": "Altre impostazioni",
"Outgoing webhook message format": "Formato messaggio webhook in uscita",
"Owner": "Proprietario",
"Password": "Password",
@@ -527,7 +527,7 @@
"Time settings": "Impostazioni dell'orario",
"Time zone": "Fuso orario",
"Time's up!": "Tempo terminato!",
"Tip: You can also send \"/poll Some question\"": "",
"Tip: You can also send \"/poll Some question\"": "Tip: Puoi anche inviare \"/poll per Qualche domanda",
"Today": "Oggi",
"Toggle subscription": "Cambia sottoscrizione",
"Tomorrow": "Domani",
@@ -600,7 +600,7 @@
"Who can create streams": "Chi può creare canali",
"Who can see users email addresses": "Chi può vedere gli indirizzi email degli utenti",
"Working\u2026": "Elaborazione...",
"Write": "",
"Write": "Scrivi",
"Yes": "Sì",
"Yes, delete this stream": "Sì, cancella questo canale",
"Yes, send": "Sì, spedisci",
@@ -629,9 +629,9 @@
"Your account": "Il tuo account",
"Your bots": "I tuoi bot",
"Your reminder note is empty!": "Il tuo promemoria è vuoto!",
"Zoom API key (required)": "",
"Zoom API secret (required)": "",
"Zoom user ID (required)": "",
"Zoom API key (required)": "Zoom API Key (richiesta)",
"Zoom API secret (required)": "Zoom API secret (richiesta)",
"Zoom user ID (required)": "Zoom user ID (richiesta)",
"[Condense this message]": "[Rimpicciolisci questo messaggio]",
"[Configure]": "[Configura]",
"[Disable]": "[Disabilita]",

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Zulip\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-03-01 17:24+0000\n"
"POT-Creation-Date: 2019-03-05 01:24+0000\n"
"PO-Revision-Date: 2018-04-11 21:06+0000\n"
"Last-Translator: Tim Abbott <tabbott@kandralabs.com>\n"
"Language-Team: Tamil (http://www.transifex.com/zulip/zulip/language/ta/)\n"
@@ -599,7 +599,8 @@ msgstr ""
#: templates/zerver/app/home.html:138
msgid ""
"\n"
" Learn more about mentions <a href=\"/help/at-mention-a-user\">\n"
" Learn more about mentions <a href=\"/help/mention-a-user-or-group"
"\">\n"
" here</a>.\n"
" "
msgstr ""
@@ -1420,11 +1421,11 @@ msgstr ""
msgid "Create organization"
msgstr ""
#: templates/zerver/deactivated.html:9
#: templates/zerver/deactivated.html:15
msgid "Deactivated organization"
msgstr ""
#: templates/zerver/deactivated.html:14
#: templates/zerver/deactivated.html:20
#, python-format
msgid ""
"\n"
@@ -3273,7 +3274,7 @@ msgstr ""
msgid "Invalid type parameter"
msgstr ""
#: zerver/lib/events.py:742
#: zerver/lib/events.py:745
msgid "Could not allocate event queue"
msgstr ""
@@ -3875,7 +3876,7 @@ msgstr ""
msgid "This user is not registered; do so from a browser."
msgstr ""
#: zerver/views/auth.py:798 zerver/views/auth.py:889
#: zerver/views/auth.py:798 zerver/views/auth.py:887
msgid "Your username or password is incorrect."
msgstr ""
@@ -3887,7 +3888,7 @@ msgstr ""
msgid "Subdomain required"
msgstr ""
#: zerver/views/auth.py:897
#: zerver/views/auth.py:895
msgid "GOOGLE_CLIENT_ID is not configured"
msgstr ""

View File

@@ -38,11 +38,11 @@
}
.user_circle_empty_line {
border-color: hsl(0, 90%, 40%);
border-color: hsl(0, 0%, 50%);
&::after {
content: '';
background: hsl(0, 90%, 40%);
background: hsl(0, 0%, 50%);
height: 1.5px; // 1px is too thin, 2px is too thick
width: 6px;
display: block;

View File

@@ -11,8 +11,7 @@
{{#if invite_only}}
<i class="fa fa-lock invite-stream-icon" title="{{t 'This is a private stream' }}" aria-label="{{t 'This is a private stream' }}"></i>
{{/if}}
{{display_recipient}}
</a>
{{display_recipient}}</a>
{{! hidden narrow icon for copy-pasting }}
<span class="copy-paste-text">&gt;</span>

View File

@@ -136,7 +136,7 @@
<p>
{% trans %}
Learn more about mentions <a href="/help/at-mention-a-user">
Learn more about mentions <a href="/help/mention-a-user-or-group">
here</a>.
{% endtrans %}
</p>

View File

@@ -31,7 +31,7 @@
<nav class="header-main rightside-userlist" id="top_navbar">
<div class="column-left">
<a class="brand no-style" href="#">
<img id="realm-logo" src="{% if night_mode %} {{ realm_night_logo }}{% else %} {{ realm_logo }} {% endif %}" alt="" class="nav-logo no-drag"/>
<img id="realm-logo" src="{{ navbar_logo_url }}" alt="" class="nav-logo no-drag"/>
</a>
</div>
<div class="column-middle" id="navbar-middle">

View File

@@ -1,4 +1,10 @@
{% extends "zerver/portico_signup.html" %}
{% block customhead %}
{{ super() }}
<meta http-equiv="refresh" content="60;URL='/'">
{% endblock %}
{% block portico_content %}
<div class="app portico-page">

View File

@@ -43,45 +43,51 @@ private stream messages:
### Public streams
| | Org admins | Stream members | Org members | Guests
|--- |--- |--- |--- |---
| Join | &#10004; | &mdash; | &#10004; |
| Add others | &#10004; | [1] | &#10004; |
| See subscriber list | &#10004; | &#10004; | &#10004; |
| See full history | &#10004; | &#10004; | &#10004; |
| See estimated traffic | &#10004; | &#10004; | &#10004; |
| Post | &#10004; | [2] | |
| Change the privacy | &#10004; | | |
| Rename | &#10004; | | |
| Edit the description | &#10004; | | |
| Remove others | &#10004; | | |
| Delete | &#10004; | | |
| | Org admins | Members | Guests
|--- |--- |--- |---
| Join | &#10004; | &#10004; |
| Unsubscribe | &#9726; | &#9726; | &#9726;
| Add others | &#10004; | &#10004; |
| See subscriber list | &#10004; | &#10004; | &#9726;
| See full history | &#10004; | &#10004; | &#9726;
| See estimated traffic | &#10004; | &#10004; | &#9726;
| Post | &#10004; | &#10038; | &#10038;
| Change the privacy | &#10004; | |
| Rename | &#10004; | |
| Edit the description | &#10004; | |
| Remove others | &#10004; | |
| Delete | &#10004; | |
[1] Yes, except for guests.
&#10004; Always
&#9726; &nbsp; If subscribed to the stream
&#10038; Configurable. Org admins and Members can, by default, post to
any public stream, and Guests can only post to public streams if they
are subscribed. Additionally, streams can be configured to only allow
administrators to post.
[2] Configurable.
### Private streams
| | Org admins | Stream members | Org members | Guests
|--- |--- |--- |--- |---
| Join | | &mdash; | |
| Add others | | [1] | |
| See subscriber list | &#10004; | &#10004; | |
| See full history | | [3] | |
| See estimated traffic | &#10004; | &#10004; | |
| Post | &#10004; | [2] | |
| Change the privacy | [4] | | |
| Rename | &#10004; | | |
| Edit the description | &#10004; | | |
| Remove others | &#10004; | | |
| Delete | &#10004; | | |
[1] Yes, except for guests.
| | Org admins | Members | Guests
|--- |--- |--- |---
| Join | | |
| Unsubscribe | &#9726; | &#9726; | &#9726;
| Add others | &#9726; | &#9726; |
| See subscriber list | &#10004; | &#9726; | &#9726;
| See full history | &#10038; | &#10038; | &#10038;
| See estimated traffic | &#10004; | &#9726; | &#9726;
| Post | &#9726; | &#10038; | &#10038;
| Change the privacy | &#9726; | |
| Rename | &#10004; | |
| Edit the description | &#10004; | |
| Remove others | &#10004; | |
| Delete | &#10004; | |
[2] Configurable.
&#10004; Always
[3] Depends on the stream type.
&#9726; &nbsp; If subscribed to the stream
[4] Yes, but only if subscribed. If you have a private stream without an
admin, you'll have to add an admin in order to change the stream's privacy.
&#10038; Configurable, but at minimum must be subscribed to the stream

View File

@@ -1,6 +1,6 @@
ZULIP_VERSION = "2.0.0"
ZULIP_VERSION = "2.0.1"
LATEST_MAJOR_VERSION = "2.0"
LATEST_RELEASE_VERSION = "2.0.0"
LATEST_RELEASE_VERSION = "2.0.1"
LATEST_RELEASE_ANNOUNCEMENT = "https://blog.zulip.org/2019/03/01/zulip-2-0-released/"
# Bump the minor PROVISION_VERSION to indicate that folks should provision

View File

@@ -15,7 +15,6 @@ from zerver.lib.bugdown import convert as bugdown_convert
from zerver.lib.send_email import FromAddress
from zerver.lib.subdomains import get_subdomain
from zerver.lib.realm_icon import get_realm_icon_url
from zerver.lib.realm_logo import get_realm_logo_url
from version import ZULIP_VERSION, LATEST_RELEASE_VERSION, \
LATEST_RELEASE_ANNOUNCEMENT, LATEST_MAJOR_VERSION
@@ -54,8 +53,6 @@ def zulip_default_context(request: HttpRequest) -> Dict[str, Any]:
realm_uri = settings.ROOT_DOMAIN_URI
realm_name = None
realm_icon = None
realm_logo = None
realm_night_logo = None
realm_description = None
realm_invite_required = False
realm_plan_type = 0
@@ -63,8 +60,6 @@ def zulip_default_context(request: HttpRequest) -> Dict[str, Any]:
realm_uri = realm.uri
realm_name = realm.name
realm_icon = get_realm_icon_url(realm)
realm_logo = get_realm_logo_url(realm, night = False)
realm_night_logo = get_realm_logo_url(realm, night = True)
realm_description_raw = realm.description or "The coolest place in the universe."
realm_description = bugdown_convert(realm_description_raw, message_realm=realm)
realm_invite_required = realm.invite_required
@@ -119,8 +114,6 @@ def zulip_default_context(request: HttpRequest) -> Dict[str, Any]:
'realm_uri': realm_uri,
'realm_name': realm_name,
'realm_icon': realm_icon,
'realm_logo': realm_logo,
'realm_night_logo': realm_night_logo,
'realm_description': realm_description,
'realm_plan_type': realm_plan_type,
'root_domain_uri': settings.ROOT_DOMAIN_URI,

View File

@@ -107,6 +107,13 @@ def get_raw_user_data(realm_id: int, client_gravatar: bool) -> Dict[int, Dict[st
for row in user_dicts
}
def add_realm_logo_fields(state: Dict[str, Any], realm: Realm) -> None:
state['realm_logo_url'] = realm_logo_url(realm, night = False)
state['realm_logo_source'] = realm.logo_source
state['realm_night_logo_url'] = realm_logo_url(realm, night = True)
state['realm_night_logo_source'] = realm.night_logo_source
state['max_logo_file_size'] = settings.MAX_LOGO_FILE_SIZE
def always_want(msg_type: str) -> bool:
'''
This function is used as a helper in
@@ -184,11 +191,7 @@ def fetch_initial_state_data(user_profile: UserProfile,
state['realm_icon_url'] = realm_icon_url(realm)
state['realm_icon_source'] = realm.icon_source
state['max_icon_file_size'] = settings.MAX_ICON_FILE_SIZE
state['realm_logo_url'] = realm_logo_url(realm, night = False)
state['realm_logo_source'] = realm.logo_source
state['realm_night_logo_url'] = realm_logo_url(realm, night = True)
state['realm_night_logo_source'] = realm.night_logo_source
state['max_logo_file_size'] = settings.MAX_LOGO_FILE_SIZE
add_realm_logo_fields(state, realm)
state['realm_bot_domain'] = realm.get_bot_domain()
state['realm_uri'] = realm.uri
state['realm_available_video_chat_providers'] = realm.VIDEO_CHAT_PROVIDERS

View File

@@ -1718,8 +1718,6 @@ class FetchAuthBackends(ZulipTestCase):
('realm_name', check_string),
('realm_description', check_string),
('realm_icon', check_string),
('realm_logo', check_string),
('realm_night_logo', check_string),
])
def test_fetch_auth_backend_format(self) -> None:
@@ -2550,19 +2548,23 @@ class TestLDAP(ZulipLDAPTestCase):
self.assertIs(user_profile, None)
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_login_failure_due_to_wrong_subdomain(self) -> None:
def test_login_success_with_different_subdomain(self) -> None:
self.mock_ldap.directory = {
'uid=hamlet,ou=users,dc=zulip,dc=com': {
'userPassword': ['testing', ]
'fn': ['King Hamlet', ],
'sn': ['Hamlet', ],
'userPassword': ['testing', ],
}
}
ldap_user_attr_map = {'full_name': 'fn', 'short_name': 'sn'}
with self.settings(
LDAP_APPEND_DOMAIN='zulip.com',
AUTH_LDAP_BIND_PASSWORD='',
AUTH_LDAP_USER_DN_TEMPLATE='uid=%(user)s,ou=users,dc=zulip,dc=com'):
user_profile = self.backend.authenticate(self.example_email("hamlet"), 'testing',
AUTH_LDAP_USER_DN_TEMPLATE='uid=%(user)s,ou=users,dc=zulip,dc=com',
AUTH_LDAP_USER_ATTR_MAP=ldap_user_attr_map):
user_profile = self.backend.authenticate(self.example_email('hamlet'), 'testing',
realm=get_realm('zephyr'))
self.assertIs(user_profile, None)
self.assertEqual(user_profile.email, self.example_email('hamlet'))
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_login_failure_due_to_invalid_subdomain(self) -> None:

View File

@@ -10,6 +10,8 @@ import urllib
from typing import Any, Dict
from zerver.lib.actions import do_create_user
from zerver.lib.actions import do_change_logo_source
from zerver.lib.events import add_realm_logo_fields
from zerver.lib.test_classes import ZulipTestCase
from zerver.lib.test_helpers import (
HostRequestMock, queries_captured, get_user_messages
@@ -20,7 +22,7 @@ from zerver.models import (
get_realm, get_stream, get_user, UserProfile,
flush_per_request_caches, DefaultStream, Realm,
)
from zerver.views.home import home, sent_time_in_epoch_seconds
from zerver.views.home import home, sent_time_in_epoch_seconds, compute_navbar_logo_url
from corporate.models import Customer, CustomerPlan
class HomeTest(ZulipTestCase):
@@ -722,6 +724,54 @@ class HomeTest(ZulipTestCase):
html = result.content.decode('utf-8')
self.assertIn('Apps for every platform.', html)
def test_compute_navbar_logo_url(self) -> None:
user_profile = self.example_user("hamlet")
page_params = {"night_mode": True}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
"/static/images/logo/zulip-org-logo.png?version=0")
page_params = {"night_mode": False}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
"/static/images/logo/zulip-org-logo.png?version=0")
do_change_logo_source(user_profile.realm, Realm.LOGO_UPLOADED, night=False)
page_params = {"night_mode": True}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
"/user_avatars/1/realm/logo.png?version=2")
page_params = {"night_mode": False}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
"/user_avatars/1/realm/logo.png?version=2")
do_change_logo_source(user_profile.realm, Realm.LOGO_UPLOADED, night=True)
page_params = {"night_mode": True}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
"/user_avatars/1/realm/night_logo.png?version=2")
page_params = {"night_mode": False}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
"/user_avatars/1/realm/logo.png?version=2")
# This configuration isn't super supported in the UI and is a
# weird choice, but we have a test for it anyway.
do_change_logo_source(user_profile.realm, Realm.LOGO_DEFAULT, night=False)
page_params = {"night_mode": True}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
"/user_avatars/1/realm/night_logo.png?version=2")
page_params = {"night_mode": False}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
"/static/images/logo/zulip-org-logo.png?version=0")
def test_generate_204(self) -> None:
email = self.example_email("hamlet")
self.login(email)

View File

@@ -38,6 +38,7 @@ from zerver.lib.actions import (
get_stream,
do_create_default_stream_group,
do_add_default_stream,
do_create_realm,
)
from zerver.lib.send_email import send_email, send_future_email, FromAddress
from zerver.lib.initial_password import initial_password
@@ -2686,6 +2687,49 @@ class UserSignUpTest(InviteUserBase):
self.assertEqual(birthday_field_value.value, '1990-12-19')
self.assertEqual(phone_number_field_value.value, 'a-new-number')
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_ldap_registration_multiple_realms(self) -> None:
password = "testing"
email = "newuser@zulip.com"
ldap_user_attr_map = {
'full_name': 'fn',
'short_name': 'sn',
}
full_name = 'New LDAP fullname'
mock_directory = {
'uid=newuser,ou=users,dc=zulip,dc=com': {
'userPassword': ['testing', ],
'fn': [full_name],
'sn': ['shortname'],
}
}
init_fakeldap(mock_directory)
do_create_realm('test', 'test', False)
with self.settings(
POPULATE_PROFILE_VIA_LDAP=True,
LDAP_APPEND_DOMAIN='zulip.com',
AUTH_LDAP_BIND_PASSWORD='',
AUTH_LDAP_USER_ATTR_MAP=ldap_user_attr_map,
AUTH_LDAP_USER_DN_TEMPLATE='uid=%(user)s,ou=users,dc=zulip,dc=com'):
subdomain = "zulip"
self.login_with_return(email, password,
HTTP_HOST=subdomain + ".testserver")
user_profile = UserProfile.objects.get(email=email, realm=get_realm('zulip'))
self.assertEqual(user_profile.email, email)
self.logout()
# Test registration in another realm works.
subdomain = "test"
self.login_with_return(email, password,
HTTP_HOST=subdomain + ".testserver")
user_profile = UserProfile.objects.get(email=email, realm=get_realm('test'))
self.assertEqual(user_profile.email, email)
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',
'zproject.backends.ZulipDummyBackend'))
def test_ldap_registration_when_names_changes_are_disabled(self) -> None:

View File

@@ -871,8 +871,6 @@ def api_get_server_settings(request: HttpRequest) -> HttpResponse:
"realm_uri",
"realm_name",
"realm_icon",
"realm_logo",
"realm_night_logo",
"realm_description"]:
if context[settings_item] is not None:
result[settings_item] = context[settings_item]

View File

@@ -1,4 +1,4 @@
from typing import List, Dict, Optional
from typing import Any, List, Dict, Optional
from django.conf import settings
from django.urls import reverse
@@ -73,6 +73,13 @@ def get_bot_types(user_profile: UserProfile) -> List[Dict[str, object]]:
})
return bot_types
def compute_navbar_logo_url(page_params: Dict[str, Any]) -> str:
if page_params["night_mode"] and page_params["realm_night_logo_source"] != Realm.LOGO_DEFAULT:
navbar_logo_url = page_params["realm_night_logo_url"]
else:
navbar_logo_url = page_params["realm_logo_url"]
return navbar_logo_url
def home(request: HttpRequest) -> HttpResponse:
if (settings.DEVELOPMENT and not settings.TEST_SUITE and
os.path.exists('var/handlebars-templates/compile.error')):
@@ -270,6 +277,9 @@ def home_real(request: HttpRequest) -> HttpResponse:
# include (and thus how to display emojis in the emoji picker
# and composebox typeahead).
emojiset = UserProfile.GOOGLE_BLOB_EMOJISET
navbar_logo_url = compute_navbar_logo_url(page_params)
response = render(request, 'zerver/app/index.html',
context={'user_profile': user_profile,
'emojiset': emojiset,
@@ -286,6 +296,7 @@ def home_real(request: HttpRequest) -> HttpResponse:
'is_admin': user_profile.is_realm_admin,
'is_guest': user_profile.is_guest,
'night_mode': user_profile.night_mode,
'navbar_logo_url': navbar_logo_url,
'show_webathena': user_profile.realm.webathena_enabled,
'enable_feedback': settings.ENABLE_FEEDBACK,
'embedded': narrow_stream is not None,

View File

@@ -451,12 +451,11 @@ class ZulipLDAPAuthBackend(ZulipLDAPAuthBackendBase):
raise ZulipLDAPException("Realm has been deactivated")
if return_data.get("inactive_user"):
raise ZulipLDAPException("User has been deactivated")
if return_data.get("invalid_subdomain"):
# TODO: Implement something in the caller for this to
# provide a nice user-facing error message for this
# situation (right now it just acts like any other auth
# failure).
raise ZulipLDAPException("Wrong subdomain")
# An invalid_subdomain `return_data` value here is ignored,
# since that just means we're trying to create an account in a
# second realm on the server (`ldap_auth_enabled(realm)` would
# have been false if this user wasn't meant to have an account
# in this second realm).
if self._realm.deactivated:
# This happens if no account exists, but the realm is
# deactivated, so we shouldn't create a new user account