1
0
mirror of https://github.com/Kovah/LinkAce.git synced 2025-01-17 13:18:21 +01:00

Implement a basic update check in the system settings (#96)

This commit is contained in:
Kovah 2020-03-04 14:53:31 +01:00
parent b6b6f57ad8
commit 54226a5eca
No known key found for this signature in database
GPG Key ID: AAAA031BA9830D7B
10 changed files with 146 additions and 1 deletions

View File

@ -0,0 +1,60 @@
<?php
namespace App\Helper;
use Composer\Semver\Comparator;
use Illuminate\Support\Facades\Http;
/**
* Class UpdateHelper
*
* @package App\Helper
*/
class UpdateHelper
{
protected static $releaseApiUrl = 'https://api.github.com/repos/kovah/linkace/releases';
/**
* Returns the version string if there is a newer version is available.
* Returns true if the check was successful, but no updates was found.
* Returns false if the check could not be executed, e.g. due to network
* issues.
*
* @return bool|string
*/
public static function checkForUpdates()
{
$currentVersion = config('linkace.version');
$latestVersion = self::getCurrentVersionFromAPI();
if ($latestVersion === null) {
return false;
}
if (Comparator::greaterThan($latestVersion, $currentVersion)) {
return $latestVersion;
}
return true;
}
/**
* We try to get the latest releases from the Github API and then get the
* tag name from the latest. If the request failed for some reason or no
* release could be found, null is returned.
*
* @return string|null
*/
protected static function getCurrentVersionFromAPI(): ?string
{
$response = Http::get(self::$releaseApiUrl);
if (!$response->successful()) {
return null;
}
$releases = $response->json();
return $releases[0]['tag_name'] ?? null;
}
}

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use App\Helper\UpdateHelper;
use App\Models\Link;
use App\Models\LinkList;
use App\Models\Tag;
@ -76,4 +77,11 @@ class FetchController extends Controller
return response()->json(['linkFound' => $linkCount > 0]);
}
public static function checkForUpdates(): JsonResponse
{
$updateCheck = UpdateHelper::checkForUpdates();
return response()->json(['checkResult' => $updateCheck]);
}
}

View File

@ -9,6 +9,7 @@ import SimpleSelect from './components/SimpleSelect';
import ShareToggleAll from './components/ShareToggleAll';
import GenerateApiToken from './components/GenerateApiToken';
import GenerateCronToken from './components/GenerateCronToken';
import UpdateCheck from './components/UpdateCheck';
// Register view components
function registerViews () {
@ -21,6 +22,7 @@ function registerViews () {
register('.share-toggle', ShareToggleAll);
register('.api-token', GenerateApiToken);
register('.cron-token', GenerateCronToken);
register('.update-check', UpdateCheck);
}
if (document.readyState !== 'loading') {

View File

@ -0,0 +1,51 @@
import { debounce } from '../lib/helper';
export default class UpdateCheck {
constructor ($el) {
this.result = null;
this.$el = $el;
this.$running = $el.querySelector('.update-check-running');
this.$versionFound = $el.querySelector('.update-check-version-found');
this.$success = $el.querySelector('.update-check-success');
this.$failed = $el.querySelector('.update-check-failed');
this.init();
}
init () {
debounce(() => {
this.checkForUpdate().then(result => {
this.result = result;
this.updateCheckStatus();
});
}, 500);
}
updateCheckStatus () {
this.$running.classList.add('d-none');
if (typeof this.result.length === 'string') {
this.$versionFound.innerText = this.$versionFound.innerText.replace('#VERSION#', this.result);
this.$versionFound.classList.remove('d-none');
} else if (this.result === true) {
this.$success.classList.remove('d-none');
} else {
this.$failed.classList.remove('d-none');
}
}
async checkForUpdate () {
return fetch(window.appData.routes.fetch.updateCheck, {
credentials: 'same-origin',
headers: {'Content-Type': 'application/json'}
}).then((response) => {
return response.json();
}).then((results) => {
return results.checkResult;
}).catch(() => {
return false;
});
}
}

View File

@ -65,4 +65,10 @@ return [
'cron_token_generate_failure' => 'A new cron token could not be generated. Please check your browser console and application logs for more information.',
'cron_token_auth_failure' => 'The provided cron token is invalid',
'cron_execute_successful' => 'Cron successfully executed',
'update_check' => 'Update Check',
'update_check_running' => 'Checking for updates...',
'update_check_version_found' => 'Update found. Version #VERSION# is available.',
'update_check_success' => 'No update found.',
'update_check_failed' => 'Could not check for updates.',
];

View File

@ -1,4 +1,4 @@
<div class="card">
<div class="card mt-4">
<div class="card-header">
@lang('settings.cron_token')
</div>

View File

@ -0,0 +1,13 @@
<div class="card">
<div class="card-header">
@lang('settings.update_check')
</div>
<div class="update-check card-body small">
<div class="update-check-running">@lang('settings.update_check_running')</div>
<div class="update-check-version-found text-success d-none">@lang('settings.update_check_version_found')</div>
<div class="update-check-success d-none">@lang('settings.update_check_success')</div>
<div class="update-check-failed text-danger d-none">@lang('settings.update_check_failed')</div>
</div>
</div>

View File

@ -2,6 +2,8 @@
@section('content')
@include('actions.settings.partials.system.updates')
@include('actions.settings.partials.system.cron')
@include('actions.settings.partials.system.general-settings')

View File

@ -31,6 +31,7 @@
'searchLists' => route('fetch-lists'),
'searchTags' => route('fetch-tags'),
'existingLinks' => route('fetch-existing-links'),
'updateCheck' => route('fetch-update-check'),
'generateApiToken' => route('generate-api-token'),
'generateCronToken' => route('generate-cron-token'),
]

View File

@ -136,6 +136,8 @@ Route::group(['middleware' => ['auth']], function () {
->name('fetch-lists');
Route::post('fetch/existing-links', [FetchController::class, 'searchExistingUrls'])
->name('fetch-existing-links');
Route::get('fetch/update-check', [FetchController::class, 'checkForUpdates'])
->name('fetch-update-check');
});
// Guest access routes