1
0
Fork 0
mirror of synced 2024-06-28 02:50:24 +12:00

Move version banner logic from JS to Python

Also adds CSS styling to banner.
This commit is contained in:
Ben Muthalaly 2023-11-27 22:56:30 -06:00
parent 7599dbb79d
commit a3fd8a8ecd
3 changed files with 111 additions and 78 deletions

View file

@ -30,6 +30,7 @@ import inspect
import getpass import getpass
import platform import platform
import shutil import shutil
import requests
import django import django
from sqlite3 import dbapi2 as sqlite3 from sqlite3 import dbapi2 as sqlite3
@ -397,6 +398,55 @@ def get_commit_hash(config):
except Exception: except Exception:
return None return None
def get_version_releases(config):
"""
returns a dictionary containing the GitHub release data for
the recommended upgrade version and the currently installed version
"""
github_releases_api = "https://api.github.com/repos/pirate/archivebox/releases"
response = requests.get(github_releases_api)
if response.status_code != 200:
stderr('Failed to get release data from GitHub', color='lightyellow', config=config)
return None
releases = response.json()
installed_version = config['VERSION']
installed_version_parts = parse_tag_name(installed_version)
# find current version or nearest older version (to link to)
current_version = None
for i, release in enumerate(releases):
release_parts = parse_tag_name(release["tag_name"])
if compare_versions(release["tag_name"], installed_version) <= 0:
current_version = release
break
current_version = current_version if current_version else releases[-1]
# find upgrade version
upgrade_version = None
smallest_version_diff = parse_tag_name(releases[0]["tag_name"])[1]
for i, release in enumerate(releases):
release_parts = parse_tag_name(release["tag_name"])
major_version_diff = release_parts[1] - installed_version_parts[1]
if major_version_diff < smallest_version_diff:
smallest_version_diff = major_version_diff
if smallest_version_diff < 1:
break
upgrade_version = release
upgrade_version = upgrade_version if upgrade_version else releases[0]
return {"upgrade_version": upgrade_version, "current_version": current_version}
def can_upgrade(config):
if config['VERSION_RELEASES']:
upgrade_version_tag = config['VERSION_RELEASES']['upgrade_version']['tag_name']
current_version_tag = config['VERSION_RELEASES']['current_version']['tag_name']
return compare_versions(upgrade_version_tag, current_version_tag) == 1
return False
############################## Derived Config ################################## ############################## Derived Config ##################################
@ -424,6 +474,8 @@ DYNAMIC_CONFIG_SCHEMA: ConfigDefaultDict = {
'ARCHIVEBOX_BINARY': {'default': lambda c: sys.argv[0] or bin_path('archivebox')}, 'ARCHIVEBOX_BINARY': {'default': lambda c: sys.argv[0] or bin_path('archivebox')},
'VERSION': {'default': lambda c: get_version(c)}, 'VERSION': {'default': lambda c: get_version(c)},
'VERSION_RELEASES': {'default': lambda c: get_version_releases(c)},
'CAN_UPGRADE': {'default': lambda c: can_upgrade(c)},
'COMMIT_HASH': {'default': lambda c: get_commit_hash(c)}, 'COMMIT_HASH': {'default': lambda c: get_commit_hash(c)},
'PYTHON_BINARY': {'default': lambda c: sys.executable}, 'PYTHON_BINARY': {'default': lambda c: sys.executable},
@ -696,6 +748,28 @@ def load_config(defaults: ConfigDefaultDict,
# with open(os.path.join(config['OUTPUT_DIR'], CONFIG_FILENAME), 'w+') as f: # with open(os.path.join(config['OUTPUT_DIR'], CONFIG_FILENAME), 'w+') as f:
def parse_tag_name(v):
"""parses a version tag string formatted like 'vx.x.x'"""
v = re.sub(r"\+.*$", "", v) # in case version string ends with '+editable'
parts = re.sub(r"^v", "", v).split(".")
return [int(p) for p in parts]
def compare_versions(v1, v2):
"""
for two version strings v1 and v2, returns 1 if v1 is newer than v2,
0 if they're equivalent and -1 if v1 is older than v2.
"""
v1Parts = parse_tag_name(v1)
v2Parts = parse_tag_name(v2)
for i in range(len(v1Parts)):
if v1Parts[i] < v2Parts[i]:
return -1
if v1Parts[i] > v2Parts[i]:
return 1
return 0
# Logging Helpers # Logging Helpers
def stdout(*args, color: Optional[str]=None, prefix: str='', config: Optional[ConfigDict]=None) -> None: def stdout(*args, color: Optional[str]=None, prefix: str='', config: Optional[ConfigDict]=None) -> None:

View file

@ -8,7 +8,7 @@ from django.views.generic.base import RedirectView
from core.views import HomepageView, SnapshotView, PublicIndexView, AddView, HealthCheckView from core.views import HomepageView, SnapshotView, PublicIndexView, AddView, HealthCheckView
from config import VERSION from config import VERSION, VERSION_RELEASES, CAN_UPGRADE
# print('DEBUG', settings.DEBUG) # print('DEBUG', settings.DEBUG)
@ -31,7 +31,7 @@ urlpatterns = [
path('accounts/', include('django.contrib.auth.urls')), path('accounts/', include('django.contrib.auth.urls')),
path('admin/', admin.site.urls, {'extra_context': {'VERSION': VERSION}}), path('admin/', admin.site.urls, {'extra_context': {'VERSION': VERSION, 'VERSION_RELEASES': VERSION_RELEASES, 'CAN_UPGRADE': CAN_UPGRADE}}),
path('health/', HealthCheckView.as_view(), name='healthcheck'), path('health/', HealthCheckView.as_view(), name='healthcheck'),
path('error/', lambda _: 1/0), path('error/', lambda _: 1/0),

View file

@ -12,7 +12,26 @@
{% endblock %} {% endblock %}
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}"> <link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}">
{% block extrastyle %}{% endblock %} {% block extrastyle %}
<style>
#upgrade-banner {
position: fixed;
right: 20px;
bottom: 20px;
background-color: #f8f8f8;
color: #333333;
border: 2px solid #772948;
padding: 10px 20px;
z-index: 1000;
text-align: center;
}
#dismiss-btn {
background: #aa1e55;
color: white;
cursor: pointer;
}
</style>
{% endblock %}
{% if LANGUAGE_BIDI %} {% if LANGUAGE_BIDI %}
<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}"> <link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}">
@ -123,99 +142,39 @@
</div> </div>
<script> <script>
const installedVersion = "{{VERSION}}"; if ("{{CAN_UPGRADE}}" === "True" && !localStorage.getItem("bannerDismissed")) {
let upgradeVersionTag = "{{VERSION_RELEASES.upgrade_version.tag_name}}"
let upgradeVersionURL= "{{VERSION_RELEASES.upgrade_version.html_url}}"
let currentVersionTag = "{{VERSION}}"
let currentVersionURL = "{{VERSION_RELEASES.current_version.html_url}}"
// get versions from GitHub createBanner(currentVersionTag, currentVersionURL, upgradeVersionTag, upgradeVersionURL)
const github_releases_api = "https://api.github.com/repos/pirate/archivebox/releases";
let release_data = fetch(github_releases_api)
.then(response => response.json())
.then(release_data => {
let upgradeVersion = findUpgradeVersion(installedVersion, release_data);
let currentVersion = findCurrentVersion(installedVersion, release_data);
const showBanner = localStorage.getItem("bannerDismissed") !== "true" && currentVersion.html_url !== upgradeVersion.html_url
if (showBanner) {
createBanner(currentVersion, upgradeVersion);
}
})
.catch(error => {
console.error('Error fetching release data: ', error);
});
// finds the nearest stable version
function findCurrentVersion(currentVersionTagName, releaseData) {
for (let i = 0; i < releaseData.length; i++) {
if (compareVersions(releaseData[i].tag_name, currentVersionTagName) <= 0) {
return releaseData[i];
}
}
return releaseData[releaseData.length - 1];
} }
function findUpgradeVersion(currentVersionTagName, releaseData) { function createBanner(currentVersionTag, currentVersionURL, upgradeVersionTag, upgradeVersionURL){
for (let i = 0; i < releaseData.length; i++) {
if (majorVersionDiff(releaseData[i].tag_name, currentVersionTagName) === 1) {
return releaseData[i];
}
}
return releaseData[0];
}
function createBanner(currentVersion, upgradeVersion) {
const banner = document.createElement('div'); const banner = document.createElement('div');
banner.setAttribute('id', 'upgrade-banner'); banner.setAttribute('id', 'upgrade-banner');
banner.innerHTML = ` banner.innerHTML = `
There's a new version of ArchiveBox available! <p>There's a new version of ArchiveBox available!</p>
The next major version is <a href=${upgradeVersion.html_url}>${upgradeVersion.tag_name}</a>. Your version: <a href=${currentVersionURL}>${currentVersionTag}</a> | New version: <a href=${upgradeVersionURL}>${upgradeVersionTag}</a>
Your current version is <a href=${currentVersion.html_url}>${installedVersion}</a>
<p> <p>
<a href=https://github.com/ArchiveBox/ArchiveBox/wiki/Upgrading-or-Merging-Archives>Upgrading</a> | <a href=https://github.com/ArchiveBox/ArchiveBox/releases>Changelog</a> | <a href=https://github.com/ArchiveBox/ArchiveBox/wiki/Roadmap>Roadmap</a> <a href=https://github.com/ArchiveBox/ArchiveBox/wiki/Upgrading-or-Merging-Archives>Upgrading</a> | <a href=https://github.com/ArchiveBox/ArchiveBox/releases>Changelog</a> | <a href=https://github.com/ArchiveBox/ArchiveBox/wiki/Roadmap>Roadmap</a>
</p> </p>
<button> <button id="dismiss-btn">Dismiss</button>
<a href="#" onclick="dismissBanner()">Dismiss</a>
</button>
` `
document.body.appendChild(banner); document.body.appendChild(banner);
let dismissButton = document.querySelector("#dismiss-btn")
if (dismissButton) {
dismissButton.addEventListener("click", dismissBanner)
}
} }
// dismisses the version banner and stores a cookie to prevent it from showing again
function dismissBanner() { function dismissBanner() {
var banner = document.getElementById("version-banner"); var banner = document.getElementById("upgrade-banner");
banner.style.display = "none"; banner.style.display = "none";
localStorage.setItem("bannerDismissed", "true"); localStorage.setItem("bannerDismissed", "true");
} }
function parseVersion(v) {
return v.replace(/^v/, '').split(".").map(Number);
}
// compares two version strings formatted like "vx.x.x" (where the x's are integers)
// and returns 1 if v1 is newer than v2, 0 if they're the same, and -1
// if v1 is older than v2.
function compareVersions(v1, v2) {
let v1Parts = parseVersion(v1);
let v2Parts = parseVersion(v2);
for (let i = 0; i < 3; i++) {
if (v1Parts[i] < v2Parts[i]) {
return -1;
}
if (v1Parts[i] > v2Parts[i]) {
return 1;
}
}
return 0;
}
function majorVersionDiff(v1, v2) {
let v1Parts = parseVersion(v1);
let v2Parts = parseVersion(v2);
return v1Parts[1] - v2Parts[1];
}
$ = django.jQuery; $ = django.jQuery;
$.fn.reverse = [].reverse; $.fn.reverse = [].reverse;