Re-implement version check

This makes LibreTime check its version against github releases and lets the user know when to update. It uses the red exclamation point when there is a patch release or if LibreTime is more than one major release ahead. The orange icon is used when LibreTime is on a git install, a single major update is available, or a pre-release version is installed. The green update icon gets used to signify that a new minor release is available. Finally the green checkmark will be used when you are on a stable release.
This commit is contained in:
Lucas Bickel 2017-03-20 20:34:23 +01:00
parent 81d3c3e2b8
commit 06a3ad0ed3
8 changed files with 230 additions and 38 deletions

View File

@ -25,6 +25,7 @@ define('AIRTIME_TRANSIFEX_URL' , 'http://libretime.org/translating/');
define('SUPPORT_TICKET_URL' , 'https://github.com/LibreTime/libretime/issues'); define('SUPPORT_TICKET_URL' , 'https://github.com/LibreTime/libretime/issues');
define('UI_REVAMP_EMBED_URL' , 'https://www.youtube.com/embed/nqpNnCKGluY'); define('UI_REVAMP_EMBED_URL' , 'https://www.youtube.com/embed/nqpNnCKGluY');
define('LIBRETIME_WHATS_NEW_URL' , 'https://github.com/LibreTime/libretime/releases'); define('LIBRETIME_WHATS_NEW_URL' , 'https://github.com/LibreTime/libretime/releases');
define('LIBRETIME_UPDATE_FEED' , 'https://github.com/LibreTime/libretime/releases.atom');
define('LIBRETIME_EMAIL_FROM' , 'noreply@libretime.org'); define('LIBRETIME_EMAIL_FROM' , 'noreply@libretime.org');
define('LICENSE_VERSION' , 'GNU AGPL v.3'); define('LICENSE_VERSION' , 'GNU AGPL v.3');

View File

@ -39,9 +39,11 @@ class LocaleController extends Zend_Controller_Action
//dashboard/versiontooltip.js //dashboard/versiontooltip.js
"You are running the latest version" => _("You are running the latest version"), "You are running the latest version" => _("You are running the latest version"),
"New version available: " => _("New version available: "), "New version available: " => _("New version available: "),
"This version will soon be obsolete." => _("This version will soon be obsolete."), "You have a pre-release version of LibreTime intalled." => _("You have a pre-release version of LibreTime intalled."),
"This version is no longer supported." => _("This version is no longer supported."), "A patch update for your LibreTime installation is available." => _("A patch update for your LibreTime installation is available."),
"Please upgrade to " => _("Please upgrade to "), "A feature update for your LibreTime installation is available." => _("A feature update for your LibreTime installation is available."),
"A major update for your LibreTime installation is available." => _("A major update for your LibreTime installation is available."),
"Multiple major updates for LibreTime installation are available. Please upgrade as soon as possible." => _("Multiple major updates for LibreTime installation are available. Please upgrade as soon as possible."),
//library/events/library_playlistbuilder.js //library/events/library_playlistbuilder.js
"Add to current playlist" => _("Add to current playlist"), "Add to current playlist" => _("Add to current playlist"),
"Add to current smart block" => _("Add to current smart block"), "Add to current smart block" => _("Add to current smart block"),

View File

@ -879,8 +879,27 @@ class Application_Model_Preference
public static function GetLatestVersion() public static function GetLatestVersion()
{ {
$config = Config::getConfig(); $config = Config::getConfig();
$latest = self::getValue("latest_version");
if ($latest == null || strlen($latest) == 0) { $latest = json_decode(self::getValue('latest_version'));
$nextCheck = self::getValue('latest_version_nextcheck');
if ($latest && $nextCheck > time()) {
return $latest;
}
$rss = new SimplePie();
$rss->set_feed_url(array(LIBRETIME_UPDATE_FEED));
$rss->enable_cache(false);
$rss->init();
$rss->handle_content_type();
// get all available versions ut to default github api limit
$versions = array();
foreach ($rss->get_items() as $item) {
$versions[] = $item->get_title();
}
$latest = $versions;
self::setValue('latest_version', json_encode($latest));
self::setValue('latest_version_nextcheck', strtotime('+1 week'));
if (empty($latest)) {
return $config['airtime_version']; return $config['airtime_version'];
} else { } else {
return $latest; return $latest;
@ -899,7 +918,7 @@ class Application_Model_Preference
{ {
$link = self::getValue("latest_link"); $link = self::getValue("latest_link");
if ($link == null || strlen($link) == 0) { if ($link == null || strlen($link) == 0) {
return 'http://airtime.sourcefabric.org'; return LIBRETIME_WHATS_NEW_URL;
} else { } else {
return $link; return $link;
} }

View File

@ -1,5 +1,8 @@
<?php <?php
use Composer\Semver\Comparator;
use Composer\Semver\Semver;
/** /**
* This file does the following things: * This file does the following things:
* 1. Calculate how many major versions back the current installation * 1. Calculate how many major versions back the current installation
@ -9,9 +12,63 @@
* (stored in pair of invisible div tags) * (stored in pair of invisible div tags)
* 4. Returns the current version, as HTML (stored in pair of invisible div tags) * 4. Returns the current version, as HTML (stored in pair of invisible div tags)
*/ */
class Airtime_View_Helper_VersionNotify extends Zend_View_Helper_Abstract{ class Airtime_View_Helper_VersionNotify extends Zend_View_Helper_Abstract {
public function versionNotify(){ public function versionNotify()
return ""; {
$config = Config::getConfig();
// retrieve and validate current and latest versions,
$current = $config['airtime_version'];
$latest = Application_Model_Preference::GetLatestVersion();
$link = Application_Model_Preference::GetLatestLink();
$isGitRelease = preg_match('/^[[:alnum:]]{7}$/i', $current) === 1;
$currentParts = array(0, 0, 0, 0);
if (!$isGitRelease) {
$currentParts = preg_split("/(\.|-)/", $current);
}
$majorCandidates = SemVer::satisfiedBy($latest, sprintf('>=%1$s', $currentParts[0] + 1));
$minorCandidates = SemVer::satisfiedBy($latest, sprintf('~%1$s.%2$s', $currentParts[0], $currentParts[1] + 1));
$patchCandidates = SemVer::satisfiedBy($latest, sprintf('>=%1$s.%2$s.%3$s <%1$s.%3$s', $currentParts[0], $currentParts[1], $currentParts[2] + 1, $currentParts[1] + 1));
$hasMajor = !empty($majorCandidates);
$hasMinor = !empty($minorCandidates);
$hasPatch = !empty($patchCandidates);
$isPreRelease = $isGitRelease || array_key_exists(4, $currentParts);
$hasMultiMajor = count($majorCandidates) > 1;
if ($isPreRelease) {
// orange "warning" if you are on unreleased code
$class = 'update2';
} else if ($hasPatch || $hasMultiMajor) {
// current patch or more than 1 major behind
$class = 'outdated';
} else if ($hasMinor) {
// green warning for feature update
$class = 'update';
} else if ($hasMajor) {
// orange warning for 1 major beind
$class = 'update2';
} else {
$class = 'uptodate';
}
$latest = SemVer::rsort($latest);
$highestVersion = $latest[0];
$data = (object) array(
'link' => $link,
'latest' => $highestVersion,
'current' => $current,
'hasPatch' => $hasPatch,
'hasMinor' => $hasMinor,
'hasMajor' => $hasMajor,
'isPreRelease' => $isPreRelease,
'hasMultiMajor' => $hasMultiMajor,
);
$result = sprintf('<script>var versionNotifyInfo = %s;</script>', json_encode($data))
. "<div id='version-icon' class='" . $class . "'></div>";
return $result;
} }
} }

View File

@ -101,8 +101,8 @@ select {
/* Version Notification Starts*/ /* Version Notification Starts*/
#version-icon { #version-icon {
position:absolute; position:absolute;
right:96px; top:68px;
top:104px; right: 196px;
height:35px; height:35px;
width:35px; width:35px;
z-index:1000; z-index:1000;

View File

@ -2,43 +2,91 @@
* Get the tooltip message to be displayed * Get the tooltip message to be displayed
*/ */
function getContent() { function getContent() {
var diff = getVersionDiff();
var link = getLatestLink(); var link = getLatestLink();
var hasPatch = getHasPatch();
var hasMinor = getHasMinor();
var hasMajor = getHasMajor();
var hasMultiMajor = getHasMultiMajor();
var isPreRelease = getIsPreRelease();
var msg = ""; var msg = "";
// See file airtime_mvc/application/views/helpers/VersionNotify.php for more info // See file airtime_mvc/application/views/helpers/VersionNotify.php for more info
if(isUpToDate()) { if(isUpToDate()) {
msg = $.i18n._("You are running the latest version"); msg = $.i18n._("You are running the latest version");
} else if (diff < 20) {
msg = $.i18n._("New version available: ") + link;
} else if (diff < 30) {
msg = $.i18n._("This version will soon be obsolete.")+"<br/>"+$.i18n._("Please upgrade to ") + link;
} else { } else {
msg = $.i18n._("This version is no longer supported.")+"<br/>"+$.i18n._("Please upgrade to ") + link; msg = $.i18n._("New version available: ") + link + '<ul>';
if (isPreRelease) {
msg += '<li>'+$.i18n._("You have a pre-release version of LibreTime intalled.");
}
if (hasPatch) {
msg += '<li>'+$.i18n._("A patch update for your LibreTime installation is available.");
}
if (hasMinor) {
msg += '<li>'+$.i18n._("A feature update for your LibreTime installation is available.");
}
if (hasMajor && !hasMultiMajor) {
msg += '<li>'+$.i18n._("A major update for your LibreTime installation is available.");
}
if (hasMultiMajor) {
msg += '<li>'+$.i18n._("Multiple major updates for LibreTime installation are available. Please upgrade as soon as possible.");
}
msg += '</ul>';
} }
return msg; return msg;
} }
/** /**
* Get major version difference b/w current and latest version, in int * Get if patch is available
*/ */
function getVersionDiff() { function getHasPatch() {
return parseInt($("#version-diff").html()); return versionNotifyInfo.hasPatch;
} }
/**
* Get if minor update is available
*/
function getHasMinor() {
return versionNotifyInfo.hasMinor;
}
/**
* Get if major update is available
*/
function getHasMajor() {
return versionNotifyInfo.hasMajor;
}
/**
* Get if multiple major updates are available
*/
function getHasMultiMajor() {
return versionNotifyInfo.hasMultiMajor;
}
/**
* Get if pre-release was installed
*/
function getIsPreRelease() {
return versionNotifyInfo.isPreRelease;
}
/** /**
* Get the current version * Get the current version
*/ */
function getCurrentVersion() { function getCurrentVersion() {
return $("#version-current").html(); return versionNotifyInfo.current;
} }
/** /**
* Get the latest version * Get the latest version
*/ */
function getLatestVersion() { function getLatestVersion() {
return $("#version-latest").html(); return versionNotifyInfo.latest;
} }
/** /**
@ -52,18 +100,14 @@ function getLatestLink() {
* Returns true if current version is up to date * Returns true if current version is up to date
*/ */
function isUpToDate() { function isUpToDate() {
var diff = getVersionDiff(); return !getHasPatch() && !getHasMinor() && !getHasMajor();
var current = getCurrentVersion();
var latest = getLatestVersion();
var temp = (diff == 0 && current == latest) || diff < 0;
return (diff == 0 && current == latest) || diff < 0;
} }
/** /**
* Opens the link in a new window * Opens the link in a new window
*/ */
function openLatestLink() { function openLatestLink() {
window.open($("#version-link").html()); window.open(versionNotifyInfo.link);
} }
/** /**
@ -103,4 +147,4 @@ $(document).ready(function() {
if($('#version-icon').length > 0) { if($('#version-icon').length > 0) {
setupVersionQtip(); setupVersionQtip();
} }
}); });

View File

@ -12,7 +12,8 @@
"ise/php-soundcloud": "3.0.1", "ise/php-soundcloud": "3.0.1",
"massivescale/celery-php": "2.0.*@dev", "massivescale/celery-php": "2.0.*@dev",
"simplepie/simplepie": "dev-master", "simplepie/simplepie": "dev-master",
"zendframework/zendframework1": "^1.12" "zendframework/zendframework1": "^1.12",
"composer/semver": "^1.4"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.3", "phpunit/phpunit": "^4.3",

82
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "33cfdc655be243bdcabe59ca6f3ca434", "content-hash": "2770ac91638846655f6d1cfc549df150",
"packages": [ "packages": [
{ {
"name": "aws/aws-sdk-php", "name": "aws/aws-sdk-php",
@ -73,6 +73,68 @@
], ],
"time": "2014-12-08T21:56:46+00:00" "time": "2014-12-08T21:56:46+00:00"
}, },
{
"name": "composer/semver",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "c7cb9a2095a074d131b65a8a0cd294479d785573"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573",
"reference": "c7cb9a2095a074d131b65a8a0cd294479d785573",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5",
"phpunit/phpunit-mock-objects": "2.3.0 || ^3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Semver\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
},
{
"name": "Rob Bast",
"email": "rob.bast@gmail.com",
"homepage": "http://robbast.nl"
}
],
"description": "Semver library that offers utilities, version constraint parsing and validation.",
"keywords": [
"semantic",
"semver",
"validation",
"versioning"
],
"time": "2016-08-30T16:08:34+00:00"
},
{ {
"name": "guzzle/guzzle", "name": "guzzle/guzzle",
"version": "v3.9.3", "version": "v3.9.3",
@ -268,7 +330,7 @@
"queue", "queue",
"task" "task"
], ],
"time": "2015-04-17T10:58:54+00:00" "time": "2015-04-17 10:58:54"
}, },
{ {
"name": "phing/phing", "name": "phing/phing",
@ -536,16 +598,22 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/simplepie/simplepie.git", "url": "https://github.com/simplepie/simplepie.git",
"reference": "6102a15d768c7d81fe48f7e2f1d8cf9e71e5959f" "reference": "eb6dd2d578dd62a1eec68b60cdda8c4a38a8de49"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/6102a15d768c7d81fe48f7e2f1d8cf9e71e5959f", "url": "https://api.github.com/repos/simplepie/simplepie/zipball/eb6dd2d578dd62a1eec68b60cdda8c4a38a8de49",
"reference": "6102a15d768c7d81fe48f7e2f1d8cf9e71e5959f", "reference": "eb6dd2d578dd62a1eec68b60cdda8c4a38a8de49",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.2.0" "php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "~4 || ~5"
},
"suggest": {
"mf2/mf2": "Microformat module that allows for parsing HTML for microformats"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -582,7 +650,7 @@
"feeds", "feeds",
"rss" "rss"
], ],
"time": "2015-09-02T01:14:05+00:00" "time": "2017-02-28 01:12:12"
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",