refactor plugins marketplace
This commit is contained in:
parent
078fcf47ec
commit
4c735aa8e4
@ -8,46 +8,28 @@ use App\Services\Unzip;
|
||||
use Composer\CaBundle\CaBundle;
|
||||
use Composer\Semver\Comparator;
|
||||
use Exception;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class MarketController extends Controller
|
||||
{
|
||||
/**
|
||||
* Guzzle HTTP client.
|
||||
*
|
||||
* @var \GuzzleHttp\Client
|
||||
*/
|
||||
protected $guzzle;
|
||||
|
||||
/**
|
||||
* Cache for plugins registry.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $registryCache;
|
||||
|
||||
public function __construct(\GuzzleHttp\Client $guzzle)
|
||||
public function marketData(PluginManager $manager, Client $client)
|
||||
{
|
||||
$this->guzzle = $guzzle;
|
||||
}
|
||||
|
||||
public function marketData(PluginManager $manager)
|
||||
{
|
||||
$plugins = collect($this->getAllAvailablePlugins())->map(function ($item) use ($manager) {
|
||||
$plugins = $this->fetch($client)->map(function ($item) use ($manager) {
|
||||
$plugin = $manager->get($item['name']);
|
||||
|
||||
if ($plugin) {
|
||||
$item['enabled'] = $plugin->isEnabled();
|
||||
$item['installed'] = $plugin->version;
|
||||
$item['update_available'] = Comparator::greaterThan($item['version'], $item['installed']);
|
||||
$item['can_update'] = Comparator::greaterThan($item['version'], $item['installed']);
|
||||
} else {
|
||||
$item['installed'] = false;
|
||||
}
|
||||
|
||||
$requirements = Arr::get($item, 'require', []);
|
||||
unset($item['require']);
|
||||
|
||||
$item['dependencies'] = [
|
||||
'all' => $requirements,
|
||||
'unsatisfied' => $manager->getUnsatisfied(new Plugin('', $item)),
|
||||
@ -59,10 +41,15 @@ class MarketController extends Controller
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
public function download(Request $request, PluginManager $manager, Unzip $unzip)
|
||||
{
|
||||
$name = $request->get('name');
|
||||
$metadata = $this->getPluginMetadata($name);
|
||||
public function download(
|
||||
Request $request,
|
||||
PluginManager $manager,
|
||||
Client $client,
|
||||
Unzip $unzip
|
||||
) {
|
||||
$name = $request->input('name');
|
||||
$plugins = $this->fetch($client);
|
||||
$metadata = $plugins->firstWhere('name', $name);
|
||||
|
||||
if (!$metadata) {
|
||||
return json(trans('admin.plugins.market.non-existent', ['plugin' => $name]), 1);
|
||||
@ -77,56 +64,38 @@ class MarketController extends Controller
|
||||
return json(trans('admin.plugins.market.unresolved'), 1, compact('reason'));
|
||||
}
|
||||
|
||||
$url = $metadata['dist']['url'];
|
||||
$pluginsDir = $manager->getPluginsDirs()->first();
|
||||
$path = storage_path("packages/$name".'_'.$metadata['version'].'.zip');
|
||||
|
||||
$path = tempnam(sys_get_temp_dir(), $name);
|
||||
try {
|
||||
$this->guzzle->get($url, [
|
||||
$client->get($metadata['dist']['url'], [
|
||||
'sink' => $path,
|
||||
'verify' => CaBundle::getSystemCaRootBundlePath(),
|
||||
]);
|
||||
$unzip->extract($path, $pluginsDir);
|
||||
$unzip->extract($path, $manager->getPluginsDirs()->first());
|
||||
} catch (Exception $e) {
|
||||
return json($e->getMessage(), 1);
|
||||
report($e);
|
||||
|
||||
return json(trans('admin.download.errors.download', ['error' => $e->getMessage()]), 1);
|
||||
}
|
||||
|
||||
return json(trans('admin.plugins.market.install-success'), 0);
|
||||
}
|
||||
|
||||
protected function getPluginMetadata($name)
|
||||
protected function fetch(Client $client): Collection
|
||||
{
|
||||
return collect($this->getAllAvailablePlugins())->firstWhere('name', $name);
|
||||
}
|
||||
|
||||
protected function getAllAvailablePlugins()
|
||||
{
|
||||
$registryVersion = 1;
|
||||
if (app()->runningUnitTests() || !$this->registryCache) {
|
||||
$registries = collect(explode(',', config('plugins.registry')));
|
||||
$this->registryCache = $registries->map(function ($registry) use ($registryVersion) {
|
||||
$plugins = collect(explode(',', config('plugins.registry')))
|
||||
->map(function ($registry) use ($client) {
|
||||
try {
|
||||
$pluginsJson = $this->guzzle->request(
|
||||
'GET',
|
||||
trim($registry),
|
||||
['verify' => \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath()]
|
||||
)->getBody();
|
||||
$body = $client->get(trim($registry), [
|
||||
'verify' => CaBundle::getSystemCaRootBundlePath(),
|
||||
])->getBody();
|
||||
} catch (Exception $e) {
|
||||
throw new Exception(trans('admin.plugins.market.connection-error', ['error' => htmlentities($e->getMessage())]));
|
||||
throw new Exception(trans('admin.plugins.market.connection-error', ['error' => $e->getMessage()]));
|
||||
}
|
||||
|
||||
$registryData = json_decode($pluginsJson, true);
|
||||
$received = Arr::get($registryData, 'version');
|
||||
abort_if(
|
||||
is_int($received) && $received != $registryVersion,
|
||||
500,
|
||||
"Only version $registryVersion of market registry is accepted."
|
||||
);
|
||||
return Arr::get(json_decode($body, true), 'packages', []);
|
||||
})
|
||||
->flatten(1);
|
||||
|
||||
return Arr::get($registryData, 'packages', []);
|
||||
})->flatten(1);
|
||||
}
|
||||
|
||||
return $this->registryCache;
|
||||
return $plugins;
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
<span v-else-if="props.column.field === 'operations'">
|
||||
<template v-if="props.row.installed">
|
||||
<button
|
||||
v-if="props.row.update_available"
|
||||
v-if="props.row.can_update"
|
||||
class="btn btn-success"
|
||||
:disabled="installing === props.row.name"
|
||||
@click="updatePlugin(props.row)"
|
||||
@ -145,7 +145,7 @@ export default {
|
||||
)
|
||||
if (code === 0) {
|
||||
toast.success(message)
|
||||
this.plugins[originalIndex].update_available = false
|
||||
this.plugins[originalIndex].can_update = false
|
||||
this.plugins[originalIndex].installed = true
|
||||
} else if (data && data.reason) {
|
||||
alertUnresolvedPlugins(message, data.reason)
|
||||
|
@ -27,7 +27,7 @@ test('render dependencies', async () => {
|
||||
test('render operation buttons', async () => {
|
||||
Vue.prototype.$http.get.mockResolvedValue([
|
||||
{
|
||||
name: 'a', dependencies: { all: {}, unsatisfied: {} }, installed: true, update_available: true,
|
||||
name: 'a', dependencies: { all: {}, unsatisfied: {} }, installed: true, can_update: true,
|
||||
},
|
||||
{
|
||||
name: 'b', dependencies: { all: {}, unsatisfied: {} }, installed: true, enabled: true,
|
||||
@ -90,7 +90,7 @@ test('update plugin', async () => {
|
||||
version: '2.0.0',
|
||||
dependencies: { all: {}, unsatisfied: {} },
|
||||
installed: '1.0.0',
|
||||
update_available: true,
|
||||
can_update: true,
|
||||
},
|
||||
])
|
||||
Vue.prototype.$http.post
|
||||
|
@ -17,24 +17,22 @@ class MarketControllerTest extends TestCase
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->actAs('superAdmin');
|
||||
$this->actingAs(factory(\App\Models\User::class, 'superAdmin')->create());
|
||||
}
|
||||
|
||||
public function testDownload()
|
||||
{
|
||||
$this->setupGuzzleClientMock();
|
||||
|
||||
// Try to download a non-existent plugin
|
||||
$this->appendToGuzzleQueue(200, [], json_encode([
|
||||
'version' => 1,
|
||||
'packages' => [],
|
||||
]));
|
||||
$this->postJson('/admin/plugins/market/download', [
|
||||
'name' => 'non-existent-plugin',
|
||||
])->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('admin.plugins.market.non-existent', ['plugin' => 'non-existent-plugin']),
|
||||
]);
|
||||
$this->postJson('/admin/plugins/market/download', ['name' => 'nope'])
|
||||
->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('admin.plugins.market.non-existent', ['plugin' => 'nope']),
|
||||
]);
|
||||
|
||||
// Unresolved plugin.
|
||||
$fakeRegistry = json_encode(['packages' => [
|
||||
@ -88,7 +86,7 @@ class MarketControllerTest extends TestCase
|
||||
public function testMarketData()
|
||||
{
|
||||
$this->setupGuzzleClientMock([
|
||||
new RequestException('Connection Error', new Request('POST', 'whatever')),
|
||||
new RequestException('Connection Error', new Request('POST', '')),
|
||||
new Response(200, [], json_encode(['version' => 1, 'packages' => [
|
||||
[
|
||||
'name' => 'fake1',
|
||||
@ -109,11 +107,9 @@ class MarketControllerTest extends TestCase
|
||||
'require' => [],
|
||||
],
|
||||
]])),
|
||||
new Response(200, [], json_encode(['version' => 0])),
|
||||
]);
|
||||
|
||||
// Expected an exception, but unable to be asserted.
|
||||
$this->getJson('/admin/plugins/market/list');
|
||||
$this->getJson('/admin/plugins/market/list')->assertStatus(500);
|
||||
|
||||
$this->mock(PluginManager::class, function ($mock) {
|
||||
$mock->shouldReceive('get')
|
||||
@ -139,8 +135,5 @@ class MarketControllerTest extends TestCase
|
||||
'dependencies',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->getJson('/admin/plugins/market/list')
|
||||
->assertJson(['message' => 'Only version 1 of market registry is accepted.']);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user