mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 04:52:12 +00:00
Compare commits
13 Commits
ffa9c1e6a3
...
2.0.1
Author | SHA1 | Date | |
---|---|---|---|
|
29b3dd0852 | ||
|
0ffc42083e | ||
|
019e5a17f0 | ||
|
177673c84e | ||
|
f6c1a31988 | ||
|
870cd00f5f | ||
|
7db599deaa | ||
|
84d2be5e0c | ||
|
d360833d7f | ||
|
bc3db1701b | ||
|
e8aca7b723 | ||
|
7a72390710 | ||
|
3ffe4ca3e5 |
@@ -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.
|
||||
|
@@ -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:**
|
||||
|
@@ -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
|
||||
|
@@ -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';
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
@@ -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,
|
||||
|
@@ -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 -%>
|
||||
}
|
||||
|
@@ -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(
|
||||
|
@@ -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);
|
||||
|
@@ -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 ""
|
||||
|
||||
|
@@ -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."
|
||||
|
@@ -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]",
|
||||
|
@@ -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 ""
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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">></span>
|
||||
|
@@ -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>
|
||||
|
@@ -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">
|
||||
|
@@ -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">
|
||||
|
@@ -43,45 +43,51 @@ private stream messages:
|
||||
|
||||
### Public streams
|
||||
|
||||
| | Org admins | Stream members | Org members | Guests
|
||||
|--- |--- |--- |--- |---
|
||||
| Join | ✔ | — | ✔ |
|
||||
| Add others | ✔ | [1] | ✔ |
|
||||
| See subscriber list | ✔ | ✔ | ✔ |
|
||||
| See full history | ✔ | ✔ | ✔ |
|
||||
| See estimated traffic | ✔ | ✔ | ✔ |
|
||||
| Post | ✔ | [2] | |
|
||||
| Change the privacy | ✔ | | |
|
||||
| Rename | ✔ | | |
|
||||
| Edit the description | ✔ | | |
|
||||
| Remove others | ✔ | | |
|
||||
| Delete | ✔ | | |
|
||||
| | Org admins | Members | Guests
|
||||
|--- |--- |--- |---
|
||||
| Join | ✔ | ✔ |
|
||||
| Unsubscribe | ◾ | ◾ | ◾
|
||||
| Add others | ✔ | ✔ |
|
||||
| See subscriber list | ✔ | ✔ | ◾
|
||||
| See full history | ✔ | ✔ | ◾
|
||||
| See estimated traffic | ✔ | ✔ | ◾
|
||||
| Post | ✔ | ✶ | ✶
|
||||
| Change the privacy | ✔ | |
|
||||
| Rename | ✔ | |
|
||||
| Edit the description | ✔ | |
|
||||
| Remove others | ✔ | |
|
||||
| Delete | ✔ | |
|
||||
|
||||
[1] Yes, except for guests.
|
||||
✔ Always
|
||||
|
||||
◾ If subscribed to the stream
|
||||
|
||||
✶ 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 | | — | |
|
||||
| Add others | | [1] | |
|
||||
| See subscriber list | ✔ | ✔ | |
|
||||
| See full history | | [3] | |
|
||||
| See estimated traffic | ✔ | ✔ | |
|
||||
| Post | ✔ | [2] | |
|
||||
| Change the privacy | [4] | | |
|
||||
| Rename | ✔ | | |
|
||||
| Edit the description | ✔ | | |
|
||||
| Remove others | ✔ | | |
|
||||
| Delete | ✔ | | |
|
||||
|
||||
[1] Yes, except for guests.
|
||||
| | Org admins | Members | Guests
|
||||
|--- |--- |--- |---
|
||||
| Join | | |
|
||||
| Unsubscribe | ◾ | ◾ | ◾
|
||||
| Add others | ◾ | ◾ |
|
||||
| See subscriber list | ✔ | ◾ | ◾
|
||||
| See full history | ✶ | ✶ | ✶
|
||||
| See estimated traffic | ✔ | ◾ | ◾
|
||||
| Post | ◾ | ✶ | ✶
|
||||
| Change the privacy | ◾ | |
|
||||
| Rename | ✔ | |
|
||||
| Edit the description | ✔ | |
|
||||
| Remove others | ✔ | |
|
||||
| Delete | ✔ | |
|
||||
|
||||
[2] Configurable.
|
||||
✔ Always
|
||||
|
||||
[3] Depends on the stream type.
|
||||
◾ 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.
|
||||
✶ Configurable, but at minimum must be subscribed to the stream
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
@@ -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:
|
||||
|
@@ -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)
|
||||
|
@@ -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:
|
||||
|
@@ -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]
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user