apps: Use GitHub API for generating the web app download link.

This commit is contained in:
Vishnu KS
2020-10-22 17:09:55 +05:30
committed by Tim Abbott
parent dfa7ce5637
commit fdea49742c
7 changed files with 137 additions and 31 deletions

View File

@@ -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);

View File

@@ -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
View 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"

View File

@@ -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/")

View 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")

View File

@@ -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)

View File

@@ -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'}),