mirror of
https://github.com/zulip/zulip.git
synced 2025-11-21 06:58:31 +00:00
apps: Use GitHub API for generating the web app download link.
This commit is contained in:
@@ -22,33 +22,13 @@ const hello_events = function () {
|
||||
};
|
||||
|
||||
const apps_events = function () {
|
||||
const ELECTRON_APP_VERSION = page_params.electron_app_version;
|
||||
const ELECTRON_APP_URL_LINUX =
|
||||
"https://github.com/zulip/zulip-desktop/releases/download/v" +
|
||||
ELECTRON_APP_VERSION +
|
||||
"/Zulip-" +
|
||||
ELECTRON_APP_VERSION +
|
||||
"-x86_64.AppImage";
|
||||
const ELECTRON_APP_URL_MAC =
|
||||
"https://github.com/zulip/zulip-desktop/releases/download/v" +
|
||||
ELECTRON_APP_VERSION +
|
||||
"/Zulip-" +
|
||||
ELECTRON_APP_VERSION +
|
||||
".dmg";
|
||||
const ELECTRON_APP_URL_WINDOWS =
|
||||
"https://github.com/zulip/zulip-desktop/releases/download/v" +
|
||||
ELECTRON_APP_VERSION +
|
||||
"/Zulip-Web-Setup-" +
|
||||
ELECTRON_APP_VERSION +
|
||||
".exe";
|
||||
|
||||
const info = {
|
||||
windows: {
|
||||
image: "/static/images/landing-page/microsoft.png",
|
||||
alt: "Windows",
|
||||
description:
|
||||
"Zulip for Windows is even better than Zulip on the web, with a cleaner look, tray integration, native notifications, and support for multiple Zulip accounts.",
|
||||
link: ELECTRON_APP_URL_WINDOWS,
|
||||
download_link: "/apps/download/windows",
|
||||
show_instructions: true,
|
||||
install_guide: "/help/desktop-app-install-guide",
|
||||
app_type: "desktop",
|
||||
@@ -58,7 +38,7 @@ const apps_events = function () {
|
||||
alt: "macOS",
|
||||
description:
|
||||
"Zulip on macOS is even better than Zulip on the web, with a cleaner look, tray integration, native notifications, and support for multiple Zulip accounts.",
|
||||
link: ELECTRON_APP_URL_MAC,
|
||||
download_link: "/apps/download/mac",
|
||||
show_instructions: true,
|
||||
install_guide: "/help/desktop-app-install-guide",
|
||||
app_type: "desktop",
|
||||
@@ -84,7 +64,7 @@ const apps_events = function () {
|
||||
alt: "Linux",
|
||||
description:
|
||||
"Zulip on the Linux desktop is even better than Zulip on the web, with a cleaner look, tray integration, native notifications, and support for multiple Zulip accounts.",
|
||||
link: ELECTRON_APP_URL_LINUX,
|
||||
download_link: "/apps/download/linux",
|
||||
show_instructions: true,
|
||||
install_guide: "/help/desktop-app-install-guide",
|
||||
app_type: "desktop",
|
||||
@@ -127,7 +107,7 @@ const apps_events = function () {
|
||||
|
||||
$(".info .platform").text(version_info.alt);
|
||||
$(".info .description").text(version_info.description);
|
||||
$(".info .desktop-download-link").attr("href", version_info.link);
|
||||
$(".info .desktop-download-link").attr("href", version_info.download_link);
|
||||
$(".download-from-google-play-store").attr("href", version_info.link);
|
||||
$(".download-from-apple-app-store").attr("href", version_info.link);
|
||||
$(".image img").attr("src", version_info.image);
|
||||
|
||||
@@ -12,7 +12,6 @@ if os.path.exists(zulip_git_version_file):
|
||||
LATEST_MAJOR_VERSION = "3.0"
|
||||
LATEST_RELEASE_VERSION = "3.0"
|
||||
LATEST_RELEASE_ANNOUNCEMENT = "https://blog.zulip.org/2020/07/16/zulip-3-0-released/"
|
||||
LATEST_DESKTOP_VERSION = "5.4.3"
|
||||
|
||||
# Versions of the desktop app below DESKTOP_MINIMUM_VERSION will be
|
||||
# prevented from connecting to the Zulip server. Versions above
|
||||
|
||||
48
zerver/lib/github.py
Normal file
48
zerver/lib/github.py
Normal file
@@ -0,0 +1,48 @@
|
||||
import json
|
||||
import logging
|
||||
|
||||
import requests
|
||||
|
||||
from zerver.lib.cache import cache_with_key
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def get_latest_github_release_version_for_repo(repo: str) -> str:
|
||||
api_url = f"https://api.github.com/repos/zulip/{repo}/releases/latest"
|
||||
try:
|
||||
return requests.get(api_url).json()["tag_name"]
|
||||
except (requests.RequestException, json.JSONDecodeError, KeyError):
|
||||
logger.error("Unable to fetch the latest release version from GitHub %s", api_url)
|
||||
return ""
|
||||
|
||||
def verify_release_download_link(link: str) -> bool:
|
||||
try:
|
||||
requests.head(link).raise_for_status()
|
||||
return True
|
||||
except requests.RequestException:
|
||||
logger.error("App download link is broken %s", link)
|
||||
return False
|
||||
|
||||
PLATFORM_TO_SETUP_FILE = {
|
||||
"linux": "Zulip-{version}-x86_64.AppImage",
|
||||
"mac": "Zulip-{version}.dmg",
|
||||
"windows": "Zulip-Web-Setup-{version}.exe",
|
||||
}
|
||||
|
||||
class InvalidPlatform(Exception):
|
||||
pass
|
||||
|
||||
@cache_with_key(lambda platform: f"download_link:{platform}", timeout=60*30)
|
||||
def get_latest_github_release_download_link_for_platform(platform: str) -> str:
|
||||
if platform not in PLATFORM_TO_SETUP_FILE:
|
||||
raise InvalidPlatform()
|
||||
|
||||
latest_version = get_latest_github_release_version_for_repo("zulip-desktop")
|
||||
if latest_version:
|
||||
if latest_version[0] in ["v", "V"]:
|
||||
latest_version = latest_version[1:]
|
||||
setup_file = PLATFORM_TO_SETUP_FILE[platform].format(version=latest_version)
|
||||
link = f"https://github.com/zulip/zulip-desktop/releases/download/v{latest_version}/{setup_file}"
|
||||
if verify_release_download_link(link):
|
||||
return link
|
||||
return "https://github.com/zulip/zulip-desktop/releases/latest"
|
||||
@@ -471,6 +471,17 @@ class AppsPageTest(ZulipTestCase):
|
||||
html = result.content.decode('utf-8')
|
||||
self.assertIn('Apps for every platform.', html)
|
||||
|
||||
def test_app_download_link_view(self) -> None:
|
||||
return_value = "https://github.com/zulip/zulip-desktop/releases/download/v5.4.3/Zulip-Web-Setup-5.4.3.exe"
|
||||
with mock.patch("zerver.views.portico.get_latest_github_release_download_link_for_platform", return_value=return_value) as m:
|
||||
result = self.client_get("/apps/download/windows")
|
||||
m.assert_called_once_with("windows")
|
||||
self.assertEqual(result.status_code, 302)
|
||||
self.assertTrue(result['Location'] == return_value)
|
||||
|
||||
result = self.client_get("/apps/download/plan9")
|
||||
self.assertEqual(result.status_code, 404)
|
||||
|
||||
class PrivacyTermsTest(ZulipTestCase):
|
||||
def test_custom_tos_template(self) -> None:
|
||||
response = self.client_get("/terms/")
|
||||
|
||||
64
zerver/tests/test_github.py
Normal file
64
zerver/tests/test_github.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import requests
|
||||
import responses
|
||||
|
||||
from zerver.lib.cache import cache_delete
|
||||
from zerver.lib.github import InvalidPlatform, get_latest_github_release_download_link_for_platform
|
||||
from zerver.lib.test_classes import ZulipTestCase
|
||||
|
||||
logger_string = "zerver.lib.github"
|
||||
|
||||
class GitHubTestCase(ZulipTestCase):
|
||||
@responses.activate
|
||||
def test_get_latest_github_release_download_link_for_platform(self) -> None:
|
||||
responses.add(responses.GET, "https://api.github.com/repos/zulip/zulip-desktop/releases/latest",
|
||||
json={"tag_name": "v5.4.3"}, status=200)
|
||||
|
||||
responses.add(responses.HEAD, "https://github.com/zulip/zulip-desktop/releases/download/v5.4.3/Zulip-Web-Setup-5.4.3.exe",
|
||||
status=302)
|
||||
self.assertEqual(
|
||||
get_latest_github_release_download_link_for_platform("windows"),
|
||||
"https://github.com/zulip/zulip-desktop/releases/download/v5.4.3/Zulip-Web-Setup-5.4.3.exe"
|
||||
)
|
||||
|
||||
responses.add(responses.HEAD, "https://github.com/zulip/zulip-desktop/releases/download/v5.4.3/Zulip-5.4.3-x86_64.AppImage",
|
||||
status=302)
|
||||
self.assertEqual(
|
||||
get_latest_github_release_download_link_for_platform("linux"),
|
||||
"https://github.com/zulip/zulip-desktop/releases/download/v5.4.3/Zulip-5.4.3-x86_64.AppImage"
|
||||
)
|
||||
|
||||
responses.add(responses.HEAD, "https://github.com/zulip/zulip-desktop/releases/download/v5.4.3/Zulip-5.4.3.dmg", status=302)
|
||||
self.assertEqual(
|
||||
get_latest_github_release_download_link_for_platform("mac"),
|
||||
"https://github.com/zulip/zulip-desktop/releases/download/v5.4.3/Zulip-5.4.3.dmg"
|
||||
)
|
||||
|
||||
api_url = "https://api.github.com/repos/zulip/zulip-desktop/releases/latest"
|
||||
responses.replace(responses.GET, api_url, body=requests.RequestException())
|
||||
cache_delete("download_link:windows")
|
||||
with self.assertLogs(logger_string, level='ERROR') as error_log:
|
||||
self.assertEqual(
|
||||
get_latest_github_release_download_link_for_platform("windows"),
|
||||
"https://github.com/zulip/zulip-desktop/releases/latest"
|
||||
)
|
||||
self.assertEqual(error_log.output, [
|
||||
f'ERROR:{logger_string}:Unable to fetch the latest release version from GitHub {api_url}'
|
||||
])
|
||||
|
||||
responses.replace(responses.GET, "https://api.github.com/repos/zulip/zulip-desktop/releases/latest",
|
||||
json={"tag_name": "5.4.4"}, status=200)
|
||||
download_link = "https://github.com/zulip/zulip-desktop/releases/download/v5.4.4/Zulip-5.4.4-x86_64.AppImage"
|
||||
responses.add(responses.HEAD, download_link, status=404)
|
||||
cache_delete("download_link:linux")
|
||||
with self.assertLogs(logger_string, level='ERROR') as error_log:
|
||||
self.assertEqual(
|
||||
get_latest_github_release_download_link_for_platform("linux"),
|
||||
"https://github.com/zulip/zulip-desktop/releases/latest"
|
||||
)
|
||||
|
||||
self.assertEqual(error_log.output, [
|
||||
f'ERROR:{logger_string}:App download link is broken {download_link}'
|
||||
])
|
||||
|
||||
with self.assertRaises(InvalidPlatform):
|
||||
get_latest_github_release_download_link_for_platform("plan9")
|
||||
@@ -6,9 +6,9 @@ from django.contrib.auth.views import redirect_to_login
|
||||
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
|
||||
from django.template.response import TemplateResponse
|
||||
|
||||
from version import LATEST_DESKTOP_VERSION
|
||||
from zerver.context_processors import get_realm_from_request, latest_info_context
|
||||
from zerver.decorator import add_google_analytics
|
||||
from zerver.lib.github import InvalidPlatform, get_latest_github_release_download_link_for_platform
|
||||
from zerver.models import Realm
|
||||
|
||||
|
||||
@@ -18,14 +18,16 @@ def apps_view(request: HttpRequest, platform: Optional[str] = None) -> HttpRespo
|
||||
return TemplateResponse(
|
||||
request,
|
||||
'zerver/apps.html',
|
||||
context={
|
||||
"page_params": {
|
||||
'electron_app_version': LATEST_DESKTOP_VERSION,
|
||||
},
|
||||
},
|
||||
)
|
||||
return HttpResponseRedirect('https://zulip.com/apps/', status=301)
|
||||
|
||||
def app_download_link_redirect(request: HttpRequest, platform: str) -> HttpResponse:
|
||||
try:
|
||||
download_link = get_latest_github_release_download_link_for_platform(platform)
|
||||
return HttpResponseRedirect(download_link, status=302)
|
||||
except InvalidPlatform:
|
||||
return TemplateResponse(request, "404.html", status=404)
|
||||
|
||||
@add_google_analytics
|
||||
def plans_view(request: HttpRequest) -> HttpResponse:
|
||||
realm = get_realm_from_request(request)
|
||||
|
||||
@@ -82,6 +82,7 @@ from zerver.views.message_flags import (
|
||||
from zerver.views.message_send import render_message_backend, send_message_backend, zcommand_backend
|
||||
from zerver.views.muting import update_muted_topic
|
||||
from zerver.views.portico import (
|
||||
app_download_link_redirect,
|
||||
apps_view,
|
||||
hello_view,
|
||||
landing_view,
|
||||
@@ -728,6 +729,7 @@ i18n_urls = [
|
||||
path('features/', landing_view, {'template_name': 'zerver/features.html'}),
|
||||
path('plans/', plans_view, name='plans'),
|
||||
path('apps/', apps_view),
|
||||
path('apps/download/<platform>', app_download_link_redirect),
|
||||
path('apps/<platform>', apps_view),
|
||||
path('team/', team_view),
|
||||
path('history/', landing_view, {'template_name': 'zerver/history.html'}),
|
||||
|
||||
Reference in New Issue
Block a user