mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-14 20:40:49 +08:00
add bonus exchange downloaded
This commit is contained in:
42
app/Console/Commands/PluginCronjob.php
Normal file
42
app/Console/Commands/PluginCronjob.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Repositories\PluginRepository;
|
||||
use Illuminate\Console\Command;
|
||||
use Nexus\Plugin\BasePlugin;
|
||||
|
||||
class PluginCronjob extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'plugin:cronjob {--action=} {--id=} {--force=}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Plugin install / update / delete cronjob handler';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$action = $this->option('action');
|
||||
$id = $this->option('id');
|
||||
$force = $this->option('force');
|
||||
$pluginRep = new PluginRepository();
|
||||
$pluginRep->cronjob($action, $id, $force);
|
||||
$log = sprintf("[%s], action: %s, id: %s, force: %s run done !", nexus()->getRequestId(), $action, $id, $force);
|
||||
$this->info($log);
|
||||
do_log($log);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ use App\Repositories\AgentAllowRepository;
|
||||
use App\Repositories\AttendanceRepository;
|
||||
use App\Repositories\ExamRepository;
|
||||
use App\Repositories\HitAndRunRepository;
|
||||
use App\Repositories\PluginRepository;
|
||||
use App\Repositories\SearchBoxRepository;
|
||||
use App\Repositories\SearchRepository;
|
||||
use App\Repositories\TagRepository;
|
||||
@@ -87,7 +88,10 @@ class Test extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$r = \Illuminate\Support\Facades\Cache::lock();
|
||||
$rep = new PluginRepository();
|
||||
// $rep->installCronjob();
|
||||
$r = $rep->getInstalledVersion('xiaomlove/nexusphp-post-like');
|
||||
dd($r);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ class Kernel extends ConsoleKernel
|
||||
$schedule->command('claim:settle')->hourly()->when(function () {
|
||||
return Carbon::now()->format('d') == '01';
|
||||
})->withoutOverlapping();
|
||||
|
||||
// $schedule->command('plugin:cronjob')->everyMinute()->withoutOverlapping();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
114
app/Filament/Resources/System/PluginResource.php
Normal file
114
app/Filament/Resources/System/PluginResource.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\System;
|
||||
|
||||
use App\Filament\Resources\System\PluginResource\Pages;
|
||||
use App\Filament\Resources\System\PluginResource\RelationManagers;
|
||||
use App\Models\Plugin;
|
||||
use Filament\Forms;
|
||||
use Filament\Resources\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Resources\Table;
|
||||
use Filament\Tables;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
use Illuminate\Support\HtmlString;
|
||||
|
||||
class PluginResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Plugin::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-plus-circle';
|
||||
|
||||
protected static ?string $navigationGroup = 'System';
|
||||
|
||||
protected static ?int $navigationSort = 99;
|
||||
|
||||
protected static bool $shouldRegisterNavigation = false;
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
return __('admin.sidebar.plugin');
|
||||
}
|
||||
|
||||
public static function getBreadcrumb(): string
|
||||
{
|
||||
return self::getNavigationLabel();
|
||||
}
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\TextInput::make('package_name')->label(__('label.plugin.package_name')),
|
||||
Forms\Components\TextInput::make('remote_url')->label(__('label.plugin.remote_url')),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('id'),
|
||||
Tables\Columns\TextColumn::make('package_name')->label(__('plugin.labels.package_name')),
|
||||
Tables\Columns\TextColumn::make('remote_url')->label(__('plugin.labels.remote_url')),
|
||||
Tables\Columns\TextColumn::make('installed_version')->label(__('plugin.labels.installed_version')),
|
||||
Tables\Columns\TextColumn::make('statusText')->label(__('label.status')),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->actions(self::getActions())
|
||||
->bulkActions([
|
||||
Tables\Actions\DeleteBulkAction::make(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ManagePlugins::route('/'),
|
||||
];
|
||||
}
|
||||
|
||||
private static function getActions()
|
||||
{
|
||||
$actions = [];
|
||||
$actions[] = Tables\Actions\EditAction::make();
|
||||
$actions[] = self::buildInstallAction();
|
||||
$actions[] = self::buildUpdateAction();
|
||||
$actions[] = Tables\Actions\DeleteAction::make('delete')
|
||||
->hidden(fn ($record) => $record->status == Plugin::STATUS_NOT_INSTALLED)
|
||||
->using(function ($record) {
|
||||
$record->update(['status' => Plugin::STATUS_PRE_DELETE]);
|
||||
});
|
||||
return $actions;
|
||||
}
|
||||
|
||||
private static function buildInstallAction()
|
||||
{
|
||||
return Tables\Actions\Action::make('install')
|
||||
->label(__('plugin.actions.install'))
|
||||
->icon('heroicon-o-arrow-down')
|
||||
->requiresConfirmation()
|
||||
->hidden(fn ($record) => $record->status == Plugin::STATUS_NORMAL)
|
||||
->action(function ($record) {
|
||||
$record->update(['status' => Plugin::STATUS_PRE_INSTALL]);
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
private static function buildUpdateAction()
|
||||
{
|
||||
return Tables\Actions\Action::make('update')
|
||||
->label(__('plugin.actions.update'))
|
||||
->icon('heroicon-o-arrow-up')
|
||||
->requiresConfirmation()
|
||||
->hidden(fn ($record) => in_array($record->status, [Plugin::STATUS_NOT_INSTALLED, Plugin::STATUS_PRE_UPDATE]))
|
||||
->action(function ($record) {
|
||||
$record->update(['status' => Plugin::STATUS_PRE_UPDATE]);
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\System\PluginResource\Pages;
|
||||
|
||||
use App\Filament\Resources\System\PluginResource;
|
||||
use Filament\Pages\Actions;
|
||||
use Filament\Resources\Pages\ManageRecords;
|
||||
|
||||
class ManagePlugins extends ManageRecords
|
||||
{
|
||||
protected static string $resource = PluginResource::class;
|
||||
|
||||
protected ?string $maxContentWidth = 'full';
|
||||
|
||||
protected function getActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ class BonusLogs extends NexusModel
|
||||
const BUSINESS_TYPE_NO_AD = 11;
|
||||
const BUSINESS_TYPE_GIFT_TO_LOW_SHARE_RATIO = 12;
|
||||
const BUSINESS_TYPE_LUCKY_DRAW = 13;
|
||||
const BUSINESS_TYPE_EXCHANGE_DOWNLOAD = 14;
|
||||
|
||||
public static array $businessTypes = [
|
||||
self::BUSINESS_TYPE_CANCEL_HIT_AND_RUN => ['text' => 'Cancel H&R'],
|
||||
@@ -40,6 +41,7 @@ class BonusLogs extends NexusModel
|
||||
self::BUSINESS_TYPE_NO_AD => ['text' => 'No ad'],
|
||||
self::BUSINESS_TYPE_GIFT_TO_LOW_SHARE_RATIO => ['text' => 'Gift to low share ratio'],
|
||||
self::BUSINESS_TYPE_LUCKY_DRAW => ['text' => 'Lucky draw'],
|
||||
self::BUSINESS_TYPE_EXCHANGE_DOWNLOAD => ['text' => 'Exchange download'],
|
||||
];
|
||||
|
||||
public static function getBonusForCancelHitAndRun()
|
||||
|
||||
32
app/Models/Plugin.php
Normal file
32
app/Models/Plugin.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
class Plugin extends NexusModel
|
||||
{
|
||||
protected $fillable = ['display_name', 'package_name', 'remote_url', 'installed_version', 'status', 'description', 'status_result'];
|
||||
|
||||
const STATUS_NOT_INSTALLED = -1;
|
||||
const STATUS_NORMAL = 0;
|
||||
|
||||
const STATUS_PRE_INSTALL = 1;
|
||||
const STATUS_INSTALLING = 2;
|
||||
const STATUS_INSTALL_FAILED = 3;
|
||||
|
||||
const STATUS_PRE_UPDATE = 11;
|
||||
const STATUS_UPDATING = 12;
|
||||
const STATUS_UPDATE_FAILED = 13;
|
||||
|
||||
const STATUS_PRE_DELETE = 101;
|
||||
const STATUS_DELETING = 102;
|
||||
const STATUS_DELETE_FAILED = 103;
|
||||
|
||||
public function statusText(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn($value, $attributes) => __('plugin.status.' . $attributes['status'])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -55,4 +55,20 @@ class BaseRepository
|
||||
return User::query()->findOrFail(intval($user), $fields);
|
||||
}
|
||||
|
||||
protected function executeCommand($command, $format = 'string'): string|array
|
||||
{
|
||||
$append = " 2>&1";
|
||||
if (!str_ends_with($command, $append)) {
|
||||
$command .= $append;
|
||||
}
|
||||
do_log("command: $command");
|
||||
$result = exec($command, $output, $result_code);
|
||||
$outputString = implode("\n", $output);
|
||||
do_log(sprintf('result_code: %s, result: %s, output: %s', $result_code, $result, $outputString));
|
||||
if ($result_code != 0) {
|
||||
throw new \RuntimeException($outputString);
|
||||
}
|
||||
return $format == 'string' ? $outputString : $output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
187
app/Repositories/PluginRepository.php
Normal file
187
app/Repositories/PluginRepository.php
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\Plugin;
|
||||
|
||||
class PluginRepository extends BaseRepository
|
||||
{
|
||||
public function cronjob($action = null, $id = null, $force = false)
|
||||
{
|
||||
if ($action == 'install' || $action === null) {
|
||||
$this->doCronjob('install', $id, $force, Plugin::STATUS_PRE_INSTALL, Plugin::STATUS_INSTALLING);
|
||||
}
|
||||
if ($action == 'delete' || $action === null) {
|
||||
$this->doCronjob('delete', $id, $force, Plugin::STATUS_PRE_DELETE, Plugin::STATUS_DELETING);
|
||||
}
|
||||
if ($action == 'update' || $action === null) {
|
||||
$this->doCronjob('update', $id, $force, Plugin::STATUS_PRE_UPDATE, Plugin::STATUS_UPDATING);
|
||||
}
|
||||
}
|
||||
|
||||
private function doCronjob($action, $id, $force, $preStatus, $doingStatus)
|
||||
{
|
||||
$query = Plugin::query();
|
||||
if (!$force) {
|
||||
$query->where('status', $preStatus);
|
||||
}
|
||||
if ($id !== null) {
|
||||
$query->where("id", $id);
|
||||
}
|
||||
$list = $query->get();
|
||||
if ($list->isEmpty()) {
|
||||
do_log("No plugin need to be $action...");
|
||||
return;
|
||||
}
|
||||
$idArr = $list->pluck('id')->toArray();
|
||||
Plugin::query()->whereIn('id', $idArr)->update(['status' => $doingStatus]);
|
||||
foreach ($list as $item) {
|
||||
match ($action) {
|
||||
'install' => $this->doInstall($item),
|
||||
'update' => $this->doUpdate($item),
|
||||
'delete' => $this->doDelete($item),
|
||||
default => throw new \InvalidArgumentException("Invalid action: $action")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public function doInstall(Plugin $plugin)
|
||||
{
|
||||
$packageName = $plugin->package_name;
|
||||
try {
|
||||
$this->execComposerConfig($plugin);
|
||||
$this->execComposerRequire($plugin);
|
||||
$output = $this->execPluginInstall($plugin);
|
||||
$version = $this->getInstalledVersion($packageName);
|
||||
do_log("success install plugin: $packageName version: $version");
|
||||
$update = [
|
||||
'status' => Plugin::STATUS_NORMAL,
|
||||
'status_result' => $output,
|
||||
'installed_version' => $version
|
||||
];
|
||||
} catch (\Throwable $throwable) {
|
||||
$update = [
|
||||
'status' => Plugin::STATUS_INSTALL_FAILED,
|
||||
'status_result' => $throwable->getMessage()
|
||||
];
|
||||
do_log("fail install plugin: " . $packageName);
|
||||
} finally {
|
||||
$this->updateResult($plugin, $update);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function doDelete(Plugin $plugin)
|
||||
{
|
||||
$packageName = $plugin->package_name;
|
||||
$removeSuccess = true;
|
||||
try {
|
||||
$output = $this->execComposerRemove($plugin);
|
||||
do_log("success remove plugin: $packageName");
|
||||
$update = [
|
||||
'status' => Plugin::STATUS_NOT_INSTALLED,
|
||||
'status_result' => $output,
|
||||
'installed_version' => null,
|
||||
];
|
||||
} catch (\Throwable $throwable) {
|
||||
$update = [
|
||||
'status' => Plugin::STATUS_DELETE_FAILED,
|
||||
'status_result' => $throwable->getMessage()
|
||||
];
|
||||
$removeSuccess = false;
|
||||
do_log("fail remove plugin: " . $packageName);
|
||||
} finally {
|
||||
if ($removeSuccess) {
|
||||
$plugin->delete();
|
||||
} else {
|
||||
$this->updateResult($plugin, $update);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function doUpdate(Plugin $plugin)
|
||||
{
|
||||
$packageName = $plugin->package_name;
|
||||
try {
|
||||
$output = $this->execComposerUpdate($plugin);
|
||||
$this->execPluginInstall($plugin);
|
||||
$version = $this->getInstalledVersion($packageName);
|
||||
do_log("success update plugin: $packageName to version: $version");
|
||||
$update = [
|
||||
'status' => Plugin::STATUS_NORMAL,
|
||||
'status_result' => $output,
|
||||
'installed_version' => $version,
|
||||
];
|
||||
} catch (\Throwable $throwable) {
|
||||
$update = [
|
||||
'status' => Plugin::STATUS_UPDATE_FAILED,
|
||||
'status_result' => $throwable->getMessage()
|
||||
];
|
||||
do_log("fail update plugin: " . $packageName);
|
||||
} finally {
|
||||
$this->updateResult($plugin, $update);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function getRepositoryKey(Plugin $plugin)
|
||||
{
|
||||
return str_replace("xiaomlove/nexusphp-", "", $plugin->package_name);
|
||||
}
|
||||
|
||||
private function execComposerConfig(Plugin $plugin)
|
||||
{
|
||||
$command = sprintf("composer config repositories.%s git %s", $this->getRepositoryKey($plugin), $plugin->remote_url);
|
||||
do_log("[COMPOSER_CONFIG]: $command");
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
|
||||
private function execComposerRequire(Plugin $plugin)
|
||||
{
|
||||
$command = sprintf("composer require %s", $plugin->package_name);
|
||||
do_log("[COMPOSER_REQUIRE]: $command");
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
|
||||
private function execComposerRemove(Plugin $plugin)
|
||||
{
|
||||
$command = sprintf("composer remove %s", $plugin->package_name);
|
||||
do_log("[COMPOSER_REMOVE]: $command");
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
|
||||
private function execComposerUpdate(Plugin $plugin)
|
||||
{
|
||||
$command = sprintf("composer update %s", $plugin->package_name);
|
||||
do_log("[COMPOSER_UPDATE]: $command");
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
|
||||
private function execPluginInstall(Plugin $plugin)
|
||||
{
|
||||
$command = sprintf("php artisan plugin install %s", $plugin->package_name);
|
||||
do_log("[PLUGIN_INSTALL]: $command");
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
|
||||
private function updateResult(Plugin $plugin, array $update)
|
||||
{
|
||||
$update['status_result'] = $update['status_result'] . "\n\nREQUEST_ID: " . nexus()->getRequestId();
|
||||
do_log("[UPDATE]: " . json_encode($update));
|
||||
$plugin->update($update);
|
||||
}
|
||||
|
||||
public function getInstalledVersion($packageName)
|
||||
{
|
||||
$command = sprintf('composer info |grep -E %s', $packageName);
|
||||
$result = $this->executeCommand($command);
|
||||
$parts = preg_split("/[\s]+/", trim($result));
|
||||
$version = $parts[1];
|
||||
if (str_contains($version, 'dev')) {
|
||||
$version .= " $parts[2]";
|
||||
}
|
||||
return $version;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user