mirror of
https://github.com/bs-community/blessing-skin-server.git
synced 2025-03-07 15:16:40 +08:00
Refactor UpdateController
This commit is contained in:
parent
e32983a1a1
commit
4c4023bbc2
@ -3,11 +3,7 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Log;
|
||||
use File;
|
||||
use Cache;
|
||||
use Storage;
|
||||
use Exception;
|
||||
use ZipArchive;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Http\Request;
|
||||
use Composer\Semver\Comparator;
|
||||
@ -15,127 +11,46 @@ use App\Services\PackageManager;
|
||||
|
||||
class UpdateController extends Controller
|
||||
{
|
||||
/**
|
||||
* Current application version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $currentVersion;
|
||||
|
||||
/**
|
||||
* Latest application version in update source.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $latestVersion;
|
||||
|
||||
/**
|
||||
* Where to get information of new application versions.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $updateSource;
|
||||
|
||||
/**
|
||||
* Updates information fetched from update source.
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
protected $updateInfo;
|
||||
|
||||
/**
|
||||
* Guzzle HTTP client.
|
||||
*
|
||||
* @var \GuzzleHttp\Client
|
||||
*/
|
||||
protected $guzzle;
|
||||
protected $error;
|
||||
protected $info = [];
|
||||
|
||||
public function __construct(\GuzzleHttp\Client $guzzle)
|
||||
{
|
||||
$this->updateSource = config('app.update_source');
|
||||
$this->currentVersion = config('app.version');
|
||||
|
||||
$this->guzzle = $guzzle;
|
||||
}
|
||||
|
||||
public function showUpdatePage()
|
||||
{
|
||||
$info = [
|
||||
'latest_version' => '',
|
||||
'current_version' => $this->currentVersion,
|
||||
'release_note' => '',
|
||||
'release_url' => '',
|
||||
'pre_release' => false,
|
||||
// Fallback to current time
|
||||
'release_time' => '',
|
||||
'new_version_available' => false,
|
||||
'latest' => Arr::get($this->getUpdateInfo(), 'latest'),
|
||||
'current' => $this->currentVersion,
|
||||
];
|
||||
|
||||
// If current update source is available
|
||||
if ($this->getUpdateInfo()) {
|
||||
$info['latest_version'] = $this->getUpdateInfo('latest_version');
|
||||
|
||||
$info['new_version_available'] = Comparator::greaterThan(
|
||||
$info['latest_version'],
|
||||
$info['current_version']
|
||||
);
|
||||
|
||||
if ($detail = $this->getReleaseInfo($info['latest_version'])) {
|
||||
$info = array_merge($info, Arr::only($detail, [
|
||||
'release_note',
|
||||
'release_url',
|
||||
'release_time',
|
||||
'pre_release',
|
||||
]));
|
||||
} else {
|
||||
// if detailed release info is not given
|
||||
$info['new_version_available'] = false;
|
||||
}
|
||||
|
||||
if (! $info['new_version_available']) {
|
||||
$info['release_time'] = Arr::get($this->getReleaseInfo($this->currentVersion), 'release_time');
|
||||
}
|
||||
}
|
||||
|
||||
$connectivity = true;
|
||||
|
||||
try {
|
||||
$this->guzzle->request('GET', $this->updateSource);
|
||||
} catch (Exception $e) {
|
||||
$connectivity = $e->getMessage();
|
||||
}
|
||||
|
||||
$extra = ['canUpdate' => $info['new_version_available']];
|
||||
return view('admin.update', compact('info', 'connectivity', 'extra'));
|
||||
$error = $this->error;
|
||||
$extra = ['canUpdate' => $this->canUpdate()];
|
||||
return view('admin.update', compact('info', 'error', 'extra'));
|
||||
}
|
||||
|
||||
public function checkUpdates()
|
||||
{
|
||||
return json([
|
||||
'latest' => $this->getUpdateInfo('latest_version'),
|
||||
'available' => $this->newVersionAvailable(),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function newVersionAvailable()
|
||||
{
|
||||
$latest = $this->getUpdateInfo('latest_version');
|
||||
|
||||
return Comparator::greaterThan($latest, $this->currentVersion) && $this->getReleaseInfo($latest);
|
||||
return json(['available' => $this->canUpdate()]);
|
||||
}
|
||||
|
||||
public function download(Request $request, PackageManager $package)
|
||||
{
|
||||
if (! $this->newVersionAvailable()) {
|
||||
if (! $this->canUpdate()) {
|
||||
return json([]);
|
||||
}
|
||||
|
||||
$url = $this->getReleaseInfo($this->latestVersion)['release_url'];
|
||||
$path = storage_path('packages/bs_'.$this->latestVersion.'.zip');
|
||||
$path = storage_path('packages/bs_'.$this->info['latest'].'.zip');
|
||||
switch ($request->get('action')) {
|
||||
case 'download':
|
||||
try {
|
||||
$package->download($url, $path)->extract(base_path());
|
||||
$package->download($this->info['url'], $path)->extract(base_path());
|
||||
return json(trans('admin.update.complete'), 0);
|
||||
} catch (Exception $e) {
|
||||
report($e);
|
||||
@ -148,36 +63,28 @@ class UpdateController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
protected function getUpdateInfo($key = null)
|
||||
protected function getUpdateInfo()
|
||||
{
|
||||
if (! $this->updateInfo) {
|
||||
// Add timestamp to control cdn cache
|
||||
$url = starts_with($this->updateSource, 'http')
|
||||
? $this->updateSource.'?v='.substr(time(), 0, -3)
|
||||
: $this->updateSource;
|
||||
|
||||
$acceptableSpec = 1;
|
||||
if (! $this->info) {
|
||||
try {
|
||||
$response = $this->guzzle->request('GET', $url)->getBody();
|
||||
$json = $this->guzzle->request('GET', $this->updateSource)->getBody();
|
||||
$info = json_decode($json, true);
|
||||
if (Arr::get($info, 'spec') == $acceptableSpec) {
|
||||
$this->info = $info;
|
||||
} else {
|
||||
$this->error = trans('admin.update.spec');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Log::error('[CheckingUpdate] Failed to get update information: '.$e->getMessage());
|
||||
}
|
||||
|
||||
if (isset($response)) {
|
||||
$this->updateInfo = json_decode($response, true);
|
||||
$this->error = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
$this->latestVersion = Arr::get($this->updateInfo, 'latest_version', $this->currentVersion);
|
||||
|
||||
if (! is_null($key)) {
|
||||
return Arr::get($this->updateInfo, $key);
|
||||
}
|
||||
|
||||
return $this->updateInfo;
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
protected function getReleaseInfo($version)
|
||||
protected function canUpdate()
|
||||
{
|
||||
return Arr::get($this->getUpdateInfo('releases'), $version);
|
||||
$this->getUpdateInfo();
|
||||
return Comparator::greaterThan(Arr::get($this->info, 'latest'), $this->currentVersion);
|
||||
}
|
||||
}
|
||||
|
@ -105,17 +105,16 @@ update:
|
||||
|
||||
up-to-date: Already up-to-date.
|
||||
available: New version available.
|
||||
pre-release-warning: This update is a pre-release, please double check before updating.
|
||||
|
||||
versions:
|
||||
latest: "Latest Version:"
|
||||
current: "Current Version:"
|
||||
|
||||
pre-release: You are now using pre-release version.
|
||||
|
||||
check-github: <a href=":url" target="_blank" class="el-button pull-right">Check GitHub Releases</a>
|
||||
button: Update Now
|
||||
|
||||
spec: Current update source is not supported.
|
||||
|
||||
cautions:
|
||||
title: Cautions
|
||||
text: |
|
||||
@ -128,7 +127,7 @@ update:
|
||||
size: "Size of package:"
|
||||
|
||||
errors:
|
||||
connection: "Unable to access to current update source. Details:"
|
||||
connection: "Unable to access to current update source. Details: :error"
|
||||
|
||||
download:
|
||||
errors:
|
||||
|
@ -110,17 +110,16 @@ update:
|
||||
|
||||
up-to-date: 已更新至最新版本。
|
||||
available: 有更新可用。
|
||||
pre-release-warning: 本次更新为预发布版,请谨慎选择是否更新。
|
||||
|
||||
versions:
|
||||
latest: 最新版本:
|
||||
current: 当前版本:
|
||||
|
||||
pre-release: 当前版本为未发布测试版
|
||||
|
||||
check-github: <a href=":url" target="_blank" class="el-button pull-right">查看 GitHub Releases</a>
|
||||
button: 马上升级
|
||||
|
||||
spec: 不支持当前的更新源。
|
||||
|
||||
cautions:
|
||||
title: 注意事项
|
||||
text: |
|
||||
@ -133,7 +132,7 @@ update:
|
||||
size: 更新包大小:
|
||||
|
||||
errors:
|
||||
connection: 无法访问当前更新源。详细信息:
|
||||
connection: 无法访问当前更新源。详细信息::error
|
||||
|
||||
download:
|
||||
errors:
|
||||
|
@ -22,20 +22,20 @@
|
||||
<h3 class="box-title">@lang('admin.update.info.title')</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
@if ($info['new_version_available'])
|
||||
@if ($extra['canUpdate'])
|
||||
<div class="callout callout-info">@lang('admin.update.info.available')</div>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="key">@lang('admin.update.info.versions.latest')</td>
|
||||
<td class="value">
|
||||
v{{ $info['latest_version'] }}
|
||||
v{{ $info['latest'] }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="key">@lang('admin.update.info.versions.current')</td>
|
||||
<td class="value">
|
||||
v{{ $info['current_version'] }}
|
||||
v{{ $info['current'] }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@ -43,10 +43,10 @@
|
||||
</table>
|
||||
@else
|
||||
|
||||
@if ($connectivity === true)
|
||||
<div class="callout callout-success">{{ trans('admin.update.info.up-to-date') }}</div>
|
||||
@if (is_string($error))
|
||||
<div class="callout callout-danger">{{ trans('admin.update.errors.connection', ['error' => $error]) }}</div>
|
||||
@else
|
||||
<div class="callout callout-danger">{{ trans('admin.update.errors.connection', ['error' => $connectivity]) }}</div>
|
||||
<div class="callout callout-success">{{ trans('admin.update.info.up-to-date') }}</div>
|
||||
@endif
|
||||
|
||||
<table class="table">
|
||||
@ -54,7 +54,7 @@
|
||||
<tr>
|
||||
<td class="key">@lang('admin.update.info.versions.current')</td>
|
||||
<td class="value">
|
||||
v{{ $info['current_version'] }}
|
||||
v{{ $info['current'] }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -32,18 +32,20 @@ class UpdateControllerTest extends TestCase
|
||||
// Can't connect to update source
|
||||
$this->appendToGuzzleQueue([
|
||||
new RequestException('Connection Error', new Request('GET', 'whatever')),
|
||||
new RequestException('Connection Error', new Request('GET', 'whatever')),
|
||||
]);
|
||||
$this->get('/admin/update')->assertSee(config('app.version'));
|
||||
|
||||
// New version available
|
||||
$time = time();
|
||||
$this->appendToGuzzleQueue(200, [], $this->generateFakeUpdateInfo('8.9.3', false, $time));
|
||||
$this->get('/admin/update')->assertSee(config('app.version'))->assertSee('8.9.3');
|
||||
// Missing `spec` field
|
||||
$this->appendToGuzzleQueue([
|
||||
new Response(200, [], json_encode(['latest' => '8.9.3', 'url' => ''])),
|
||||
]);
|
||||
$this->get('/admin/update')->assertSee(trans('admin.update.spec'));
|
||||
|
||||
// Now using pre-release version
|
||||
$this->appendToGuzzleQueue(200, [], $this->generateFakeUpdateInfo('0.0.1', false, $time));
|
||||
$this->get('/admin/update');
|
||||
// New version available
|
||||
$this->appendToGuzzleQueue([
|
||||
new Response(200, [], $this->mockFakeUpdateInfo('8.9.3')),
|
||||
]);
|
||||
$this->get('/admin/update')->assertSee(config('app.version'))->assertSee('8.9.3');
|
||||
}
|
||||
|
||||
public function testCheckUpdates()
|
||||
@ -53,21 +55,12 @@ class UpdateControllerTest extends TestCase
|
||||
// Update source is unavailable
|
||||
$this->appendToGuzzleQueue([
|
||||
new RequestException('Connection Error', new Request('GET', 'whatever')),
|
||||
new RequestException('Connection Error', new Request('GET', 'whatever')),
|
||||
]);
|
||||
$this->getJson('/admin/update/check')
|
||||
->assertJson([
|
||||
'latest' => null,
|
||||
'available' => false,
|
||||
]);
|
||||
$this->getJson('/admin/update/check')->assertJson(['available' => false]);
|
||||
|
||||
// New version available
|
||||
$this->appendToGuzzleQueue(200, [], $this->generateFakeUpdateInfo('8.9.3', false, time()));
|
||||
$this->getJson('/admin/update/check')
|
||||
->assertJson([
|
||||
'latest' => '8.9.3',
|
||||
'available' => true,
|
||||
]);
|
||||
$this->appendToGuzzleQueue(200, [], $this->mockFakeUpdateInfo('8.9.3'));
|
||||
$this->getJson('/admin/update/check')->assertJson(['available' => true]);
|
||||
}
|
||||
|
||||
public function testDownload()
|
||||
@ -80,8 +73,8 @@ class UpdateControllerTest extends TestCase
|
||||
|
||||
// Download
|
||||
$this->appendToGuzzleQueue([
|
||||
new Response(200, [], $this->generateFakeUpdateInfo('8.9.3')),
|
||||
new Response(200, [], $this->generateFakeUpdateInfo('8.9.3')),
|
||||
new Response(200, [], $this->mockFakeUpdateInfo('8.9.3')),
|
||||
new Response(200, [], $this->mockFakeUpdateInfo('8.9.3')),
|
||||
]);
|
||||
app()->instance(PackageManager::class, new Concerns\FakePackageManager(null, true));
|
||||
$this->getJson('/admin/update/download?action=download')
|
||||
@ -95,7 +88,7 @@ class UpdateControllerTest extends TestCase
|
||||
->assertSee('0');
|
||||
|
||||
// Invalid action
|
||||
$this->appendToGuzzleQueue(200, [], $this->generateFakeUpdateInfo('8.9.3'));
|
||||
$this->appendToGuzzleQueue(200, [], $this->mockFakeUpdateInfo('8.9.3'));
|
||||
$this->getJson('/admin/update/download?action=no')
|
||||
->assertJson([
|
||||
'errno' => 1,
|
||||
@ -103,23 +96,12 @@ class UpdateControllerTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
protected function generateFakeUpdateInfo($version, $preview = false, $time = null)
|
||||
protected function mockFakeUpdateInfo($version)
|
||||
{
|
||||
$time = $time ?: time();
|
||||
|
||||
return json_encode([
|
||||
'app_name' => 'blessing-skin-server',
|
||||
'latest_version' => $version,
|
||||
'update_time' => $time,
|
||||
'releases' => [
|
||||
$version => [
|
||||
'version' => $version,
|
||||
'pre_release' => $preview,
|
||||
'release_time' => $time,
|
||||
'release_note' => 'test',
|
||||
'release_url' => "https://whatever.test/$version/update.zip",
|
||||
],
|
||||
],
|
||||
'spec' => 1,
|
||||
'latest' => $version,
|
||||
'url' => "https://whatever.test/$version/update.zip",
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user