parent
eb62e04c1c
commit
f9b32c8e69
@ -82,6 +82,15 @@ class MarketController extends Controller
|
||||
return json(trans('admin.plugins.market.non-existent', ['plugin' => $name]), 1);
|
||||
}
|
||||
|
||||
$fakePlugin = new Plugin('', $metadata);
|
||||
$unsatisfied = $manager->getUnsatisfied($fakePlugin);
|
||||
$conflicts = $manager->getConflicts($fakePlugin);
|
||||
if ($unsatisfied->isNotEmpty() || $conflicts->isNotEmpty()) {
|
||||
$reason = $manager->formatUnresolved($unsatisfied, $conflicts);
|
||||
|
||||
return json(trans('admin.plugins.market.unresolved'), 1, compact('reason'));
|
||||
}
|
||||
|
||||
$url = $metadata['dist']['url'];
|
||||
$filename = Arr::last(explode('/', $url));
|
||||
$pluginsDir = $manager->getPluginsDirs()->first();
|
||||
|
@ -59,27 +59,7 @@ class PluginController extends Controller
|
||||
if ($result === true) {
|
||||
return json(trans('admin.plugins.operations.enabled', ['plugin' => $plugin->title]), 0);
|
||||
} else {
|
||||
$unsatisfied = $result['unsatisfied']->map(function ($detail, $name) use ($plugins) {
|
||||
$constraint = $detail['constraint'];
|
||||
if (! $detail['version']) {
|
||||
$plugin = $plugins->get($name);
|
||||
$name = $plugin ? trans($plugin->title) : $name;
|
||||
|
||||
return trans('admin.plugins.operations.unsatisfied.disabled', compact('name'));
|
||||
} else {
|
||||
$title = trans($plugins->get($name)->title);
|
||||
|
||||
return trans('admin.plugins.operations.unsatisfied.version', compact('title', 'constraint'));
|
||||
}
|
||||
})->values()->all();
|
||||
|
||||
$conflicts = $result['conflicts']->map(function ($detail, $name) use ($plugins) {
|
||||
$title = trans($plugins->get($name)->title);
|
||||
|
||||
return trans('admin.plugins.operations.unsatisfied.conflict', compact('title'));
|
||||
})->values()->all();
|
||||
|
||||
$reason = array_merge($unsatisfied, $conflicts);
|
||||
$reason = $plugins->formatUnresolved($result['unsatisfied'], $result['conflicts']);
|
||||
|
||||
return json(trans('admin.plugins.operations.unsatisfied.notice'), 1, compact('reason'));
|
||||
}
|
||||
|
@ -405,6 +405,36 @@ class PluginManager
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the "unresolved" information into human-readable text.
|
||||
*/
|
||||
public function formatUnresolved(
|
||||
Collection $unsatisfied,
|
||||
Collection $conflicts
|
||||
): array {
|
||||
$unsatisfied = $unsatisfied->map(function ($detail, $name) {
|
||||
$constraint = $detail['constraint'];
|
||||
if (! $detail['version']) {
|
||||
$plugin = $this->get($name);
|
||||
$name = $plugin ? trans($plugin->title) : $name;
|
||||
|
||||
return trans('admin.plugins.operations.unsatisfied.disabled', compact('name'));
|
||||
} else {
|
||||
$title = trans($this->get($name)->title);
|
||||
|
||||
return trans('admin.plugins.operations.unsatisfied.version', compact('title', 'constraint'));
|
||||
}
|
||||
})->values()->all();
|
||||
|
||||
$conflicts = $conflicts->map(function ($detail, $name) {
|
||||
$title = trans($this->get($name)->title);
|
||||
|
||||
return trans('admin.plugins.operations.unsatisfied.conflict', compact('title'));
|
||||
})->values()->all();
|
||||
|
||||
return array_merge($unsatisfied, $conflicts);
|
||||
}
|
||||
|
||||
/**
|
||||
* The plugins path.
|
||||
*
|
||||
|
@ -0,0 +1,19 @@
|
||||
import { showModal } from '../../scripts/notify'
|
||||
|
||||
export default function (message: string, reason: string[]): void {
|
||||
const div = document.createElement('div')
|
||||
const p = document.createElement('p')
|
||||
p.textContent = message
|
||||
div.appendChild(p)
|
||||
const ul = document.createElement('ul')
|
||||
reason.forEach(item => {
|
||||
const li = document.createElement('li')
|
||||
li.textContent = item
|
||||
ul.appendChild(li)
|
||||
})
|
||||
div.appendChild(ul)
|
||||
showModal({
|
||||
mode: 'alert',
|
||||
dangerousHTML: div.outerHTML,
|
||||
})
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import Vue from 'vue'
|
||||
import { showModal, toast } from '../../scripts/notify'
|
||||
import alertUnresolvedPlugins from './alertUnresolvedPlugins'
|
||||
|
||||
export default Vue.extend({
|
||||
data: () => ({ plugins: [] }),
|
||||
@ -32,21 +33,7 @@ export default Vue.extend({
|
||||
toast.success(message)
|
||||
this.$set(this.plugins[originalIndex], 'enabled', true)
|
||||
} else {
|
||||
const div = document.createElement('div')
|
||||
const p = document.createElement('p')
|
||||
p.textContent = message
|
||||
div.appendChild(p)
|
||||
const ul = document.createElement('ul')
|
||||
reason.forEach(item => {
|
||||
const li = document.createElement('li')
|
||||
li.textContent = item
|
||||
ul.appendChild(li)
|
||||
})
|
||||
div.appendChild(ul)
|
||||
showModal({
|
||||
mode: 'alert',
|
||||
dangerousHTML: div.outerHTML,
|
||||
})
|
||||
alertUnresolvedPlugins(message, reason)
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -73,6 +73,7 @@
|
||||
<script>
|
||||
import { VueGoodTable } from 'vue-good-table'
|
||||
import 'vue-good-table/dist/vue-good-table.min.css'
|
||||
import alertUnresolvedPlugins from '../../components/mixins/alertUnresolvedPlugins'
|
||||
import enablePlugin from '../../components/mixins/enablePlugin'
|
||||
import tableOptions from '../../components/mixins/tableOptions'
|
||||
import emitMounted from '../../components/mixins/emitMounted'
|
||||
@ -134,7 +135,11 @@ export default {
|
||||
async installPlugin({ name, originalIndex }) {
|
||||
this.installing = name
|
||||
|
||||
const { code, message } = await this.$http.post(
|
||||
const {
|
||||
code,
|
||||
message,
|
||||
data,
|
||||
} = await this.$http.post(
|
||||
'/admin/plugins/market/download',
|
||||
{ name },
|
||||
)
|
||||
@ -142,6 +147,8 @@ export default {
|
||||
toast.success(message)
|
||||
this.plugins[originalIndex].update_available = false
|
||||
this.plugins[originalIndex].installed = true
|
||||
} else if (data && data.reason) {
|
||||
alertUnresolvedPlugins(message, data.reason)
|
||||
} else {
|
||||
toast.error(message)
|
||||
}
|
||||
|
@ -57,6 +57,11 @@ test('install plugin', async () => {
|
||||
])
|
||||
Vue.prototype.$http.post
|
||||
.mockResolvedValueOnce({ code: 1, message: '1' })
|
||||
.mockResolvedValueOnce({
|
||||
code: 1,
|
||||
message: 'unresolved',
|
||||
data: { reason: ['u'] },
|
||||
})
|
||||
.mockResolvedValueOnce({ code: 0, message: '0' })
|
||||
const wrapper = mount(Market)
|
||||
await flushPromises()
|
||||
@ -68,6 +73,11 @@ test('install plugin', async () => {
|
||||
'/admin/plugins/market/download',
|
||||
{ name: 'd' },
|
||||
)
|
||||
|
||||
button.trigger('click')
|
||||
await flushPromises()
|
||||
expect(showModal).toBeCalledWith(expect.objectContaining({ mode: 'alert' }))
|
||||
|
||||
button.trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.text()).toContain('admin.enablePlugin')
|
||||
|
@ -134,6 +134,7 @@ plugins:
|
||||
not-found: No such plugin.
|
||||
|
||||
market:
|
||||
unresolved: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't download it. Please install or update the plugins listed below, and disable those have conflicts.
|
||||
connection-error: Unable to connect to the plugins registry. :error
|
||||
non-existent: The plugin :plugin does not exist.
|
||||
install-success: Plugin was installed.
|
||||
|
@ -125,6 +125,7 @@ plugins:
|
||||
no-readme-notice: The plugin doesn't contain a readme file.
|
||||
not-found: No existe dicho plugin.
|
||||
market:
|
||||
unresolved: Hay conflictos o dependencias insatisfechas en el plugin, por lo tanto no podemos descargar. Por favor, instale o actualice los plugins listados a continuación, y desactive los que tienen conflictos.
|
||||
connection-error: No se puede conectar al registro de plugins. :error
|
||||
non-existent: El plugin :plugin no existe.
|
||||
install-success: Se instaló el plugin.
|
||||
|
@ -125,6 +125,7 @@ plugins:
|
||||
no-readme-notice: 这个插件没有说明文件。
|
||||
not-found: 插件不存在
|
||||
market:
|
||||
unresolved: 无法下载此插件,因为其仍有冲突或未满足的依赖关系。请检查以下插件的版本,更新或安装它们并禁用存在冲突的插件:
|
||||
connection-error: 无法连接至插件市场源,错误信息::error
|
||||
non-existent: 插件 :plugin 不存在
|
||||
install-success: 插件安装成功
|
||||
|
@ -32,6 +32,7 @@
|
||||
- Fixed fallback when unknown locale is detected.
|
||||
- Fixed compatibility with PHP 7.4.
|
||||
- Fixed the display problem for too long texture name.
|
||||
- Fixed that dependencies and conflicts haven't been checked before installing plugin.
|
||||
|
||||
## Removed
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
- 修复不能针对未知语言进行降级的问题
|
||||
- 与 PHP 7.4 的兼容问题
|
||||
- 材质名过长时的显示问题
|
||||
- 下载插件前不检查依赖和冲突的问题
|
||||
|
||||
## 移除
|
||||
|
||||
|
@ -36,6 +36,26 @@ class MarketControllerTest extends TestCase
|
||||
'message' => trans('admin.plugins.market.non-existent', ['plugin' => 'non-existent-plugin']),
|
||||
]);
|
||||
|
||||
// Unresolved plugin.
|
||||
$fakeRegistry = json_encode(['packages' => [
|
||||
[
|
||||
'name' => 'fake',
|
||||
'version' => '0.0.0',
|
||||
'require' => ['a' => '^4.0.0'],
|
||||
],
|
||||
]]);
|
||||
$this->appendToGuzzleQueue([new Response(200, [], $fakeRegistry)]);
|
||||
$this->postJson('/admin/plugins/market/download', ['name' => 'fake'])
|
||||
->assertJson([
|
||||
'message' => trans('admin.plugins.market.unresolved'),
|
||||
'code' => 1,
|
||||
'data' => [
|
||||
'reason' => [
|
||||
trans('admin.plugins.operations.unsatisfied.disabled', ['name' => 'a']),
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
// Download
|
||||
$fakeRegistry = json_encode(['packages' => [
|
||||
[
|
||||
@ -51,9 +71,8 @@ class MarketControllerTest extends TestCase
|
||||
->once()
|
||||
->andThrow(new \Exception());
|
||||
});
|
||||
$this->postJson('/admin/plugins/market/download', [
|
||||
'name' => 'fake',
|
||||
])->assertJson(['code' => 1]);
|
||||
$this->postJson('/admin/plugins/market/download', ['name' => 'fake'])
|
||||
->assertJson(['code' => 1]);
|
||||
|
||||
$this->appendToGuzzleQueue([new Response(200, [], $fakeRegistry)]);
|
||||
$this->mock(PackageManager::class, function ($mock) {
|
||||
@ -65,9 +84,11 @@ class MarketControllerTest extends TestCase
|
||||
->with(base_path('plugins'))
|
||||
->once();
|
||||
});
|
||||
$this->postJson('/admin/plugins/market/download', [
|
||||
'name' => 'fake',
|
||||
])->assertJson(['code' => 0, 'message' => trans('admin.plugins.market.install-success')]);
|
||||
$this->postJson('/admin/plugins/market/download', ['name' => 'fake'])
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('admin.plugins.market.install-success')
|
||||
]);
|
||||
}
|
||||
|
||||
public function testCheckUpdates()
|
||||
|
Loading…
Reference in New Issue
Block a user