diff --git a/app/Console/Commands/Test.php b/app/Console/Commands/Test.php
index 39efff59..03783499 100644
--- a/app/Console/Commands/Test.php
+++ b/app/Console/Commands/Test.php
@@ -14,12 +14,10 @@ use Illuminate\Console\Command;
use NexusPlugin\Menu\Filament\MenuItemResource\Pages\ManageMenuItems;
use NexusPlugin\Menu\MenuRepository;
use NexusPlugin\Menu\Models\MenuItem;
-use NexusPlugin\Permission\Models\Permission;
use NexusPlugin\Permission\Models\Role;
use NexusPlugin\PostLike\PostLikeRepository;
use NexusPlugin\StickyPromotion\Models\StickyPromotion;
use NexusPlugin\StickyPromotion\Models\StickyPromotionParticipator;
-use NexusPlugin\Tracker\TrackerRepository;
use NexusPlugin\Work\Models\RoleWork;
use NexusPlugin\Work\WorkRepository;
use Stichoza\GoogleTranslate\GoogleTranslate;
@@ -57,9 +55,9 @@ class Test extends Command
*/
public function handle()
{
- $a = [1,2,3];
- $b = array_slice($a, 0, 2);
- dd($a, $b);
+ $rep = new MenuRepository();
+ $result = \Nexus\Plugin\Plugin::listEnabled();
+ dd($result);
}
}
diff --git a/app/Console/ExecuteCommandTrait.php b/app/Console/ExecuteCommandTrait.php
deleted file mode 100644
index 73240d55..00000000
--- a/app/Console/ExecuteCommandTrait.php
+++ /dev/null
@@ -1,16 +0,0 @@
-info("Running $command ...");
- $result = exec($command, $output, $result_code);
- do_log(sprintf('command: %s, result_code: %s, output: %s, result: %s', $command, $result_code, json_encode($output), $result));
- if ($result_code != 0) {
- throw new \RuntimeException(json_encode($output));
- }
- }
-}
diff --git a/app/Filament/Resources/System/PluginResource.php b/app/Filament/Resources/System/PluginResource.php
index fe6aa57c..eec15ff5 100644
--- a/app/Filament/Resources/System/PluginResource.php
+++ b/app/Filament/Resources/System/PluginResource.php
@@ -35,7 +35,7 @@ class PluginResource extends Resource
return self::getNavigationLabel();
}
- protected static bool $shouldRegisterNavigation = true;
+ protected static bool $shouldRegisterNavigation = false;
public static function form(Form $form): Form
{
diff --git a/app/Filament/Resources/System/PluginStoreResource.php b/app/Filament/Resources/System/PluginStoreResource.php
index 30f5104d..7a105f59 100644
--- a/app/Filament/Resources/System/PluginStoreResource.php
+++ b/app/Filament/Resources/System/PluginStoreResource.php
@@ -18,6 +18,7 @@ use Filament\Infolists\Components;
use Filament\Infolists;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
+use Illuminate\Support\Facades\App;
use Illuminate\Support\HtmlString;
use Filament\Actions\Action;
use Livewire\Livewire;
@@ -29,6 +30,13 @@ class PluginStoreResource extends Resource
protected static ?string $navigationGroup = 'System';
+ protected static ?int $navigationSort = 99;
+
+ public static function getNavigationBadge(): ?string
+ {
+ return PluginStore::getHasNewVersionCount();
+ }
+
public static function form(Form $form): Form
{
return $form
@@ -43,15 +51,26 @@ class PluginStoreResource extends Resource
->columns([
Tables\Columns\Layout\Stack::make([
Tables\Columns\Layout\Stack::make([
- Tables\Columns\TextColumn::make('title')
+ Tables\Columns\TextColumn::make(self::getColumnLabelKey("title"))
->weight(FontWeight::Bold)
,
- Tables\Columns\TextColumn::make('description'),
+ Tables\Columns\TextColumn::make(self::getColumnLabelKey("description")),
]),
Tables\Columns\Layout\Stack::make([
Tables\Columns\TextColumn::make('version')
- ->formatStateUsing(fn (PluginStore $record) => sprintf("版本: %s | 更新时间: %s", $record->version, $record->release_date))
- ->color('gray')
+ ->formatStateUsing(function (PluginStore $record) {
+ $installedVersion = $record->installed_version;
+ $latestVersion = $record->version;
+ if ($installedVersion) {
+ return sprintf('%s: %s', nexus_trans("plugin.labels.installed_version"), $installedVersion);
+ }
+ return sprintf(
+ '%s: %s | %s: %s',
+ nexus_trans("plugin.labels.latest_version"), $latestVersion,
+ nexus_trans("plugin.labels.release_date"), $record->release_date
+ );
+ })
+ ->color(fn ($record) => $record->installed_version ? 'success' : 'gray')
,
])
])->space(3),
@@ -65,24 +84,29 @@ class PluginStoreResource extends Resource
])
->actions([
Tables\Actions\ViewAction::make()
- ->modalHeading("详细介绍")
+ ->modalHeading(nexus_trans("plugin.labels.introduce"))
->modalContent(fn (PluginStore $record) => $record->getFullDescription())
->extraModalFooterActions([
- Action::make("viewOnBlog")
+ Action::make(nexus_trans("plugin.labels.view_on_blog"))
->url(fn (PluginStore $record) => $record->getBlogPostUrl())
->extraAttributes(['target' => '_blank'])
,
])
,
Tables\Actions\Action::make("install")
- ->label("安装")
- ->modalHeading(fn (PluginStore $record) => sprintf("安装插件: %s", $record->title))
+ ->label(function(PluginStore $record) {
+ if ($record->hasNewVersion()) {
+ return sprintf('%s(new: %s)', nexus_trans("plugin.actions.update"), $record->version);
+ }
+ return nexus_trans("plugin.actions.install");
+ })
+ ->modalHeading(fn (PluginStore $record) => sprintf("%s: %s", nexus_trans("plugin.actions.install_or_update") ,$record->title))
->modalContent(function (PluginStore $record) {
$infolist = new Infolist();
$infolist->record = $record;
$infolist->schema([
Infolists\Components\TextEntry::make('plugin_id')
- ->label(fn () => sprintf("进入目录: %s, 以 root 用户的身份依次执行以下命令进行安装: ", base_path()))
+ ->label(fn () => nexus_trans("plugin.labels.install_title", ['web_root' => base_path()]))
->html(true)
->formatStateUsing(function (PluginStore $record) {
return self::getPluginInstruction($record);
@@ -92,6 +116,7 @@ class PluginStoreResource extends Resource
return $infolist;
})
->modalFooterActions(fn () => [])
+ ->color(fn (PluginStore $record) => $record->hasNewVersion() ? 'danger' : 'primary')
,
])
->recordAction(null)
@@ -99,14 +124,23 @@ class PluginStoreResource extends Resource
;
}
+ private static function getColumnLabelKey($column): string
+ {
+ $locale = App::getLocale();
+ if (in_array($locale, ['zh_CN', 'zh_TW'])) {
+ return "$column.zh_CN";
+ }
+ return "$column.en";
+ }
+
private static function getPluginInstruction(PluginStore $record): string
{
$result = [];
- $result[] = "配置扩展地址";
+ $result[] = nexus_trans("plugin.labels.config_plugin_address");
$result[] = sprintf("composer config repositories.%s git %s", $record->plugin_id, $record->remote_url);
- $result[] = "
下载扩展. 这里展示的最新版本号, 如果需要安装其他版本(可在查看页面底部获得)自行替换";
+ $result[] = "
" . nexus_trans("plugin.labels.download_specific_version");
$result[] = sprintf("composer require %s:%s", $record->package_name, $record->version);
- $result[] = "
执行安装";
+ $result[] = "
" . nexus_trans("plugin.labels.execute_install");
$result[] = sprintf("php artisan plugin install %s", $record->package_name);
return implode("
", $result);
}
diff --git a/app/Filament/Resources/System/SeedBoxRecordResource.php b/app/Filament/Resources/System/SeedBoxRecordResource.php
index 60c6f90e..c4f33f67 100644
--- a/app/Filament/Resources/System/SeedBoxRecordResource.php
+++ b/app/Filament/Resources/System/SeedBoxRecordResource.php
@@ -29,7 +29,7 @@ class SeedBoxRecordResource extends Resource
protected static ?string $navigationGroup = 'System';
- protected static ?int $navigationSort = 98;
+ protected static ?int $navigationSort = 8;
public static function getNavigationLabel(): string
{
diff --git a/app/Filament/Resources/System/SettingResource.php b/app/Filament/Resources/System/SettingResource.php
index 7a515580..8022a8a4 100644
--- a/app/Filament/Resources/System/SettingResource.php
+++ b/app/Filament/Resources/System/SettingResource.php
@@ -24,7 +24,7 @@ class SettingResource extends Resource
protected static ?string $navigationGroup = 'System';
- protected static ?int $navigationSort = 100;
+ protected static ?int $navigationSort = 1000;
public static function getNavigationLabel(): string
{
diff --git a/app/Filament/Resources/System/TorrentStateResource.php b/app/Filament/Resources/System/TorrentStateResource.php
index f33e6c1b..fb8c3c91 100644
--- a/app/Filament/Resources/System/TorrentStateResource.php
+++ b/app/Filament/Resources/System/TorrentStateResource.php
@@ -24,7 +24,7 @@ class TorrentStateResource extends Resource
protected static ?string $navigationGroup = 'System';
- protected static ?int $navigationSort = 99;
+ protected static ?int $navigationSort = 9;
public static function getNavigationLabel(): string
{
diff --git a/app/Models/PluginStore.php b/app/Models/PluginStore.php
index 6e3ee7f2..7f073c02 100644
--- a/app/Models/PluginStore.php
+++ b/app/Models/PluginStore.php
@@ -5,20 +5,35 @@ namespace App\Models;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Route;
use Illuminate\Support\HtmlString;
+use Nexus\Database\NexusDB;
use Sushi\Sushi;
+use Nexus\Plugin\Plugin;
class PluginStore extends Model
{
use Sushi;
+ protected $casts = [
+ 'title' => 'array',
+ 'description' => 'array',
+ ];
+
const PLUGIN_LIST_API = "https://nppl.nexusphp.workers.dev";
const BLOG_POST_INFO_API = "https://nexusphp.org/wp-json/wp/v2/posts/%d";
const BLOG_POST_URL = "https://nexusphp.org/?p=%d";
+ private static array|null $rows =null;
+
public function getRows()
{
- return Http::get(self::PLUGIN_LIST_API)->json();
+ $list = self::listAll(true);
+ $enabled = Plugin::listEnabled();
+ foreach ($list as &$row) {
+ $row['installed_version'] = $enabled[$row['plugin_id']] ?? '';
+ }
+ return $list;
}
public function getBlogPostUrl(): string
@@ -30,7 +45,7 @@ class PluginStore extends Model
{
$url = $this->getBlogPostInfoUrl($this->post_id);
$logPrefix = sprintf("post_id: %s, url: %s", $this->post_id, $url);
- $defaultContent = "无法获取详细信息 ...";
+ $defaultContent = "Fail to get content ...";
try {
$result = Http::get($url)->json();
do_log("$logPrefix, result: " . json_encode($result));
@@ -50,8 +65,69 @@ class PluginStore extends Model
return sprintf(self::BLOG_POST_INFO_API, $postId);
}
+ public function hasNewVersion(): bool
+ {
+ return $this->installed_version
+ && version_compare($this->version, $this->installed_version, '>');
+ }
+
public static function getInfo(string $id)
{
return Http::get(self::PLUGIN_LIST_API . "/plugin/$id")->json();
}
+
+ public static function listAll($withoutCache = false)
+ {
+ $log = "listAll, withoutCache: $withoutCache";
+ $cacheKey = "nexus_plugin_store_all";
+ $cacheTime = 86400*100;
+ if (is_null(self::$rows)) {
+ $log .= ", is_null";
+ if ($withoutCache) {
+ $log .= ", WITHOUT_CACHE";
+ self::$rows = self::listAllFromRemote();
+ NexusDB::cache_put($cacheKey, self::$rows, $cacheTime);
+ } else {
+ $log .= ", WITH_CACHE";
+ self::$rows = NexusDB::remember($cacheKey, $cacheTime, function () {
+ return self::listAllFromRemote();
+ });
+ }
+ } else {
+ $log .= ", not_null";
+ }
+ do_log($log, 'debug');
+ return self::$rows;
+ }
+
+ private static function listAllFromRemote()
+ {
+ $list = Http::get(self::PLUGIN_LIST_API)->json();
+ foreach ($list as &$row) {
+ foreach ($row as $key => $value) {
+ if (is_array($value)) {
+ $row[$key] = json_encode($value);
+ }
+ }
+ }
+ return $list;
+ }
+
+ public static function getHasNewVersionCount(): int
+ {
+ $currentRouteName = Route::currentRouteName();
+ $withoutCacheRouteName = ['filament.admin.resources.system.plugin-stores.index', 'filament.admin.pages.dashboard'];
+ $list = self::listAll(in_array($currentRouteName, $withoutCacheRouteName));
+ $enabled = Plugin::listEnabled();
+ $count = 0;
+ foreach ($list as $row) {
+ $installedVersion = $enabled[$row['plugin_id']] ?? '';
+ if ($installedVersion && version_compare($installedVersion, $row['version'], '<=')) {
+ $count++;
+ }
+ }
+ return $count;
+ }
+
+
}
diff --git a/app/Policies/PluginStorePolicy.php b/app/Policies/PluginStorePolicy.php
new file mode 100644
index 00000000..4152d0c0
--- /dev/null
+++ b/app/Policies/PluginStorePolicy.php
@@ -0,0 +1,74 @@
+can($user);
+ }
+
+ /**
+ * Determine whether the user can view the model.
+ */
+ public function view(User $user, PluginStore $pluginStore): bool
+ {
+ return $this->can($user);
+ }
+
+ /**
+ * Determine whether the user can create models.
+ */
+ public function create(User $user): bool
+ {
+ return false;
+ }
+
+ /**
+ * Determine whether the user can update the model.
+ */
+ public function update(User $user, PluginStore $pluginStore): bool
+ {
+ return false;
+ }
+
+ /**
+ * Determine whether the user can delete the model.
+ */
+ public function delete(User $user, PluginStore $pluginStore): bool
+ {
+ return false;
+ }
+
+ /**
+ * Determine whether the user can restore the model.
+ */
+ public function restore(User $user, PluginStore $pluginStore): bool
+ {
+ return false;
+ }
+
+ /**
+ * Determine whether the user can permanently delete the model.
+ */
+ public function forceDelete(User $user, PluginStore $pluginStore): bool
+ {
+ return false;
+ }
+
+ private function can(User $user)
+ {
+ if ($user->class >= User::CLASS_SYSOP) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/app/Support/StaticMake.php b/app/Support/StaticMake.php
new file mode 100644
index 00000000..3019bec7
--- /dev/null
+++ b/app/Support/StaticMake.php
@@ -0,0 +1,14 @@
+getId();
+ }
}
diff --git a/nexus/Plugin/Plugin.php b/nexus/Plugin/Plugin.php
index 14ac4a9d..07439547 100644
--- a/nexus/Plugin/Plugin.php
+++ b/nexus/Plugin/Plugin.php
@@ -5,6 +5,9 @@ class Plugin
{
private static mixed $providers = null;
+ /**
+ * @var BasePlugin[]
+ */
private static array $plugins = [];
// public function __construct()
@@ -28,7 +31,7 @@ class Plugin
$result = [];
//plugins are more exactly
foreach (self::$plugins as $id => $plugin) {
- $result[$id] = 1;
+ $result[$id] = $plugin->getVersion();
}
return $result;
}
@@ -60,15 +63,19 @@ class Plugin
if ($parts[0] == 'NexusPlugin') {
$className = str_replace('ServiceProvider', 'Repository', $provider);
if (class_exists($className)) {
- $constantName = "$className::COMPATIBLE_VERSION";
+ $constantName = "$className::COMPATIBLE_NP_VERSION";
if (defined($constantName) && version_compare(VERSION_NUMBER, constant($constantName), '<')) {
continue;
}
+ /**
+ * @var BasePlugin $className
+ */
$plugin = new $className;
- $pluginIdName = "$className::ID";
- if (defined($pluginIdName)) {
- self::$plugins[constant($pluginIdName)] = $plugin;
- }
+// $pluginIdName = "$className::ID";
+// if (defined($pluginIdName)) {
+// self::$plugins[constant($pluginIdName)] = $plugin;
+// }
+ self::$plugins[$plugin->getId()] = $plugin;
call_user_func([$plugin, 'boot']);
}
}
diff --git a/resources/lang/en/plugin.php b/resources/lang/en/plugin.php
index 620799db..dcc5e8d1 100644
--- a/resources/lang/en/plugin.php
+++ b/resources/lang/en/plugin.php
@@ -2,17 +2,26 @@
return [
'actions' => [
- 'install' => 'Install',
- 'delete' => 'Remove',
- 'update' => 'Upgrade',
+ 'install' => 'install',
+ 'delete' => 'delete',
+ 'update' => 'upgrade',
+ 'install_or_update' => 'install/upgrade',
],
'labels' => [
- 'display_name' => 'Name',
- 'package_name' => 'Package name',
- 'remote_url' => 'Repository address',
- 'installed_version' => 'Installed version',
- 'status' => 'Status',
- 'updated_at' => 'Last action at',
+ 'display_name' => 'name',
+ 'package_ name' => 'package_name',
+ 'remote_url' => 'repository_address',
+ 'installed_version' => 'installed_version',
+ 'latest_version' => 'latest_version',
+ 'status' => 'status',
+ 'updated_at' => 'last_executed_action',
+ ' release_date' => 'updated at',
+ 'install_title' => 'Go to the directory: :web_root, and run the following commands in order to install it as the root user: ',
+ 'introduce' => 'Details',
+ 'view_on_blog' => 'View on blog',
+ ' config_plugin_address' => 'Configure plugin address',
+ 'download_specific_version' => 'Download the extension. The latest version is shown here, if you need to install another version (view on blog to see all versions) replace it yourself',
+ 'execute_install' => 'Execute installation',
],
'status' => [
\App\Models\Plugin::STATUS_NORMAL => 'Normal',
diff --git a/resources/lang/zh_CN/plugin.php b/resources/lang/zh_CN/plugin.php
index 7ef18c10..32bff412 100644
--- a/resources/lang/zh_CN/plugin.php
+++ b/resources/lang/zh_CN/plugin.php
@@ -5,14 +5,23 @@ return [
'install' => '安装',
'delete' => '删除',
'update' => '升级',
+ 'install_or_update' => '安装/升级',
],
'labels' => [
'display_name' => '名称',
'package_name' => '包名',
'remote_url' => '仓库地址',
'installed_version' => '已安装版本',
+ 'latest_version' => '最新版本',
'status' => '状态',
'updated_at' => '上次执行操作',
+ 'release_date' => '更新时间',
+ 'install_title' => '进入目录: :web_root, 以 root 用户的身份依次执行以下命令进行安装: ',
+ 'introduce' => '详细介绍',
+ 'view_on_blog' => '在博客上查看',
+ 'config_plugin_address' => '配置插件地址',
+ 'download_specific_version' => '下载扩展. 这里展示的最新版本号, 如果需要安装其他版本(打开查看页面底部有显示所有版本)自行替换',
+ 'execute_install' => '执行安装',
],
'status' => [
\App\Models\Plugin::STATUS_NORMAL => '正常',
diff --git a/resources/lang/zh_TW/plugin.php b/resources/lang/zh_TW/plugin.php
index a3700e24..2da80f05 100644
--- a/resources/lang/zh_TW/plugin.php
+++ b/resources/lang/zh_TW/plugin.php
@@ -5,14 +5,23 @@ return [
'install' => '安裝',
'delete' => '刪除',
'update' => '升級',
+ 'install_or_update' => '安裝/升級',
],
'labels' => [
'display_name' => '名稱',
'package_name' => '包名',
'remote_url' => '倉庫地址',
'installed_version' => '已安裝版本',
+ 'latest_version' => '最新版本',
'status' => '狀態',
'updated_at' => '上次執行操作',
+ 'release_date' => '更新時間',
+ 'install_title' => '進入目錄: :web_root, 以 root 用戶的身份依次執行以下命令進行安裝: ',
+ 'introduce' => '詳細介紹',
+ 'view_on_blog' => '在博客上查看',
+ 'config_plugin_address' => '配置插件地址',
+ 'download_specific_version' => '下載擴展. 這裏展示的最新版本號, 如果需要安裝其他版本(打開查看頁面底部有顯示所有版本)自行替換',
+ 'execute_install' => '執行安裝',
],
'status' => [
\App\Models\Plugin::STATUS_NORMAL => '正常',