diff --git a/static/js/panels.js b/static/js/panels.js index 8c2daf87e1..7110ee0b94 100644 --- a/static/js/panels.js +++ b/static/js/panels.js @@ -80,6 +80,8 @@ export function initialize() { const ls = localstorage(); if (page_params.insecure_desktop_app) { open($("[data-process='insecure-desktop-app']")); + } else if (page_params.server_needs_upgrade) { + open($("[data-process='server-needs-upgrade']")); } else if (page_params.warn_no_email === true && page_params.is_admin) { // if email has not been set up and the user is the admin, // display a warning to tell them to set up an email server. diff --git a/templates/zerver/app/navbar_alerts.html b/templates/zerver/app/navbar_alerts.html index c71281144e..25444d78f5 100644 --- a/templates/zerver/app/navbar_alerts.html +++ b/templates/zerver/app/navbar_alerts.html @@ -45,6 +45,15 @@ × +
+
+ {{ _("This Zulip server is running an old version and should be upgraded.") }} + + {{ _("Learn more.") }} + +
+ × +
{% trans count=page_params.unread_msgs.count %} diff --git a/zerver/lib/home.py b/zerver/lib/home.py index 4890f66102..d3eddafc31 100644 --- a/zerver/lib/home.py +++ b/zerver/lib/home.py @@ -1,11 +1,15 @@ import calendar +import datetime +import os import time from dataclasses import dataclass from typing import Any, Dict, List, Optional, Tuple +import pytz from django.conf import settings from django.http import HttpRequest from django.utils import translation +from django.utils.timezone import now as timezone_now from two_factor.utils import default_device from zerver.lib.events import do_events_register @@ -35,6 +39,33 @@ class UserPermissionInfo: show_webathena: bool +# LAST_SERVER_UPGRADE_TIME is the last time the server had a version deployed. +if settings.PRODUCTION: # nocoverage + timestamp = os.path.basename(os.path.abspath(settings.DEPLOY_ROOT)) + LAST_SERVER_UPGRADE_TIME = datetime.datetime.strptime(timestamp, "%Y-%m-%d-%H-%M-%S").replace( + tzinfo=pytz.utc + ) +else: + LAST_SERVER_UPGRADE_TIME = timezone_now() + + +def is_outdated_server(user_profile: Optional[UserProfile]) -> bool: + # TODO: We should ideally be using the minimum of this calculation + # and the date the release tarball was generated. + tzaware_last_upgrade_time = LAST_SERVER_UPGRADE_TIME + deadline = tzaware_last_upgrade_time + datetime.timedelta( + days=settings.SERVER_UPGRADE_NAG_DEADLINE + ) + + if user_profile is None or not user_profile.is_realm_admin: + # Administrators get warned at the deadline; all users 30 days later. + deadline = deadline + datetime.timedelta(days=30) + + if timezone_now() > deadline: + return True + return False + + def get_furthest_read_time(user_profile: Optional[UserProfile]) -> Optional[float]: if user_profile is None: return time.time() @@ -174,6 +205,7 @@ def build_page_params_for_home_page_load( test_suite=settings.TEST_SUITE, poll_timeout=settings.POLL_TIMEOUT, insecure_desktop_app=insecure_desktop_app, + server_needs_upgrade=is_outdated_server(user_profile), login_page=settings.HOME_NOT_LOGGED_IN, root_domain_uri=settings.ROOT_DOMAIN_URI, save_stacktraces=settings.SAVE_FRONTEND_STACKTRACES, diff --git a/zerver/tests/test_home.py b/zerver/tests/test_home.py index 1fc26246e5..176d0fb1cc 100644 --- a/zerver/tests/test_home.py +++ b/zerver/tests/test_home.py @@ -5,6 +5,7 @@ from typing import Any from unittest.mock import patch import orjson +import pytz from django.conf import settings from django.http import HttpResponse from django.utils.timezone import now as timezone_now @@ -17,10 +18,10 @@ from zerver.lib.actions import ( do_create_user, ) from zerver.lib.events import add_realm_logo_fields -from zerver.lib.home import get_furthest_read_time +from zerver.lib.home import LAST_SERVER_UPGRADE_TIME, get_furthest_read_time, is_outdated_server from zerver.lib.soft_deactivation import do_soft_deactivate_users from zerver.lib.test_classes import ZulipTestCase -from zerver.lib.test_helpers import get_user_messages, queries_captured +from zerver.lib.test_helpers import get_user_messages, override_settings, queries_captured from zerver.lib.users import compute_show_invites_and_add_streams from zerver.models import ( DefaultStream, @@ -211,6 +212,7 @@ class HomeTest(ZulipTestCase): "server_inline_image_preview", "server_inline_url_embed_preview", "server_name_changes_disabled", + "server_needs_upgrade", "settings_send_digest_emails", "starred_message_counts", "starred_messages", @@ -874,6 +876,27 @@ class HomeTest(ZulipTestCase): compute_navbar_logo_url(page_params), "/static/images/logo/zulip-org-logo.svg?version=0" ) + @override_settings(SERVER_UPGRADE_NAG_DEADLINE=365) + def test_is_outdated_server(self) -> None: + # Check when server_upgrade_nag_deadline > last_server_upgrade_time + hamlet = self.example_user("hamlet") + iago = self.example_user("iago") + now = LAST_SERVER_UPGRADE_TIME.replace(tzinfo=pytz.utc) + with patch("zerver.lib.home.timezone_now", return_value=now + timedelta(days=10)): + self.assertEqual(is_outdated_server(iago), False) + self.assertEqual(is_outdated_server(hamlet), False) + self.assertEqual(is_outdated_server(None), False) + + with patch("zerver.lib.home.timezone_now", return_value=now + timedelta(days=397)): + self.assertEqual(is_outdated_server(iago), True) + self.assertEqual(is_outdated_server(hamlet), True) + self.assertEqual(is_outdated_server(None), True) + + with patch("zerver.lib.home.timezone_now", return_value=now + timedelta(days=380)): + self.assertEqual(is_outdated_server(iago), True) + self.assertEqual(is_outdated_server(hamlet), False) + self.assertEqual(is_outdated_server(None), False) + def test_furthest_read_time(self) -> None: msg_id = self.send_test_message("hello!", sender_name="iago") diff --git a/zproject/default_settings.py b/zproject/default_settings.py index 541285558c..ce29143fb6 100644 --- a/zproject/default_settings.py +++ b/zproject/default_settings.py @@ -441,3 +441,6 @@ NAGIOS_BOT_HOST = EXTERNAL_HOST # Use half of the available CPUs for data import purposes. DEFAULT_DATA_EXPORT_IMPORT_PARALLELISM = (len(os.sched_getaffinity(0)) // 2) or 1 + +# How long after the last upgrade to nag users that the server is insecure +SERVER_UPGRADE_NAG_DEADLINE = 365