初始化本地仓库

This commit is contained in:
2026-08-31 11:33:59 +08:00
commit 663f74b633
2390 changed files with 402918 additions and 0 deletions
@@ -0,0 +1,158 @@
<?php
declare(strict_types=1);
namespace app\adminapi\controller\plugin;
use app\adminapi\controller\Crud;
use app\adminapi\middleware\AccessTokenMiddleware;
use app\adminapi\middleware\OperationMiddleware;
use app\adminapi\middleware\PermissionMiddleware;
use app\adminapi\schema\request\plugin\ApplicationAuthFormRequest;
use app\adminapi\schema\request\plugin\ApplicationAuthQueryRequest;
use app\adminapi\schema\response\plugin\ApplicationAuthResponse;
use app\adminapi\validate\plugin\ApplicationAuthValidate;
use app\schema\request\BatchDeleteRequest;
use app\schema\request\IdRequest;
use app\service\admin\plugin\ApplicationAuthService;
use core\tool\Json;
use madong\swagger\annotation\response\PageResponse;
use madong\swagger\annotation\response\SimpleResponse;
use madong\swagger\attribute\Permission;
use OpenApi\Attributes as OA;
use support\annotation\Middleware;
use support\Request;
use WebmanTech\Swagger\DTO\SchemaConstants;
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
final class ApplicationAuthController extends Crud
{
public function __construct(ApplicationAuthService $service, ApplicationAuthValidate $validate)
{
$this->service = $service;
$this->validate = $validate;
}
#[OA\Get(
path: '/plugin/application-auth',
summary: '列表',
tags: ['应用授权'],
x: [SchemaConstants::X_SCHEMA_REQUEST => ApplicationAuthQueryRequest::class]
)]
#[Permission(code: 'plugin:application-auth:list')]
#[PageResponse(schema: ApplicationAuthResponse::class, example: [])]
public function index(Request $request): \support\Response
{
return parent::index($request);
}
#[OA\Get(
path: '/plugin/application-auth/{id}',
summary: '详情',
tags: ['应用授权'],
x: [
SchemaConstants::X_PROPERTY_IN => 'id',
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
]
)]
#[Permission(code: 'plugin:application-auth:read')]
#[SimpleResponse(schema: ApplicationAuthResponse::class, example: [])]
public function show(Request $request): \support\Response
{
return parent::show($request);
}
#[OA\Post(
path: '/plugin/application-auth',
summary: '创建',
tags: ['应用授权'],
x: [SchemaConstants::X_SCHEMA_REQUEST => ApplicationAuthFormRequest::class]
)]
#[Permission(code: 'plugin:application-auth:create')]
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
public function store(Request $request): \support\Response
{
return parent::store($request);
}
#[OA\Put(
path: '/plugin/application-auth/{id}',
summary: '更新',
tags: ['应用授权'],
x: [SchemaConstants::X_SCHEMA_REQUEST => ApplicationAuthFormRequest::class]
)]
#[OA\Parameter(
name: 'id',
description: 'ID',
in: 'path',
required: true,
schema: new OA\Schema(type: 'string', example: '123456789012345678')
)]
#[Permission(code: 'plugin:application-auth:update')]
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
public function update(Request $request): \support\Response
{
return parent::update($request);
}
#[OA\Post(
path: '/plugin/application-auth/export',
summary: '导出',
tags: ['应用授权']
)]
#[Permission(code: 'plugin:application-auth:list', description: '导出')]
#[SimpleResponse(schema: [], example: [])]
public function export(Request $request): \support\Response
{
return parent::export($request);
}
#[OA\Delete(
path: '/plugin/application-auth/{id}',
summary: '删除',
tags: ['应用授权'],
x: [
SchemaConstants::X_PROPERTY_IN => 'id',
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
]
)]
#[Permission(code: 'plugin:application-auth:delete')]
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
public function destroy(Request $request): \support\Response
{
return parent::destroy($request);
}
#[OA\Delete(
path: '/plugin/application-auth',
summary: '批量删除',
tags: ['应用授权'],
x: [SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class]
)]
#[Permission(code: 'plugin:application-auth:delete')]
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
public function batchDelete(Request $request): \support\Response
{
return parent::destroy($request);
}
#[OA\Post(
path: '/plugin/application-auth/{id}/reset-secret',
summary: '重置密钥',
tags: ['应用授权'],
x: [
SchemaConstants::X_PROPERTY_IN => 'id',
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
]
)]
#[Permission(code: 'plugin:application-auth:reset-secret')]
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => ['id' => '123456789012345678', 'secret_key' => 'SK...']])]
public function resetSecret(Request $request): \support\Response
{
try {
$id = $request->route->param('id');
return Json::success('ok', $this->service->resetSecret($id));
} catch (\Throwable $e) {
return Json::fail($e->getMessage());
}
}
}
@@ -0,0 +1,482 @@
<?php
declare(strict_types=1);
/**
*+------------------
* madong
*+------------------
* Copyright (c) https://gitee.com/motion-code All rights reserved.
*+------------------
* Author: Mr. April (405784684@qq.com)
*+------------------
* Official Website: http://www.madong.tech
*/
namespace app\adminapi\controller\plugin;
use app\adminapi\controller\Base;
use app\adminapi\middleware\AccessTokenMiddleware;
use app\adminapi\middleware\OperationMiddleware;
use app\adminapi\middleware\PermissionMiddleware;
use app\service\core\plugin\PluginDownloadService;
use app\service\core\plugin\PluginInstallService;
use app\service\core\plugin\PluginRemoteService;
use app\service\core\plugin\PluginUninstallService;
use app\service\core\plugin\PluginService;
use core\tool\Sse;
use madong\swagger\annotation\response\PageResponse;
use madong\swagger\attribute\Permission;
use core\tool\Json;
use madong\swagger\annotation\response\SimpleResponse;
use OpenApi\Attributes as OA;
use support\annotation\Middleware;
use support\Container;
use support\Request;
use support\Response;
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
final class PluginController extends Base
{
#[OA\Get(
path: '/plugin',
summary: '列表',
tags: ['模块市场'],
parameters: [
new OA\Parameter(
name: 'page',
description: '页码',
in: 'query',
required: false,
schema: new OA\Schema(type: 'integer', default: 1)
),
new OA\Parameter(
name: 'limit',
description: '每页数量',
in: 'query',
required: false,
schema: new OA\Schema(type: 'integer', default: 10)
),
new OA\Parameter(
name: 'type',
description: '模块类型(module: 系统模块, plugin: 插件)',
in: 'query',
required: false,
schema: new OA\Schema(type: 'string', enum: ['module', 'plugin'])
),
new OA\Parameter(
name: 'status',
description: '状态(0:禁用,1:启用)',
in: 'query',
required: false,
schema: new OA\Schema(type: 'integer', enum: [0, 1])
),
new OA\Parameter(
name: 'keyword',
description: '搜索关键词',
in: 'query',
required: false,
schema: new OA\Schema(type: 'string')
),
new OA\Parameter(
name: 'installed',
description: '是否已安装(0:未安装,1:已安装)',
in: 'query',
required: false,
schema: new OA\Schema(type: 'integer', enum: [0, 1])
),
],
)]
#[PageResponse(schema: [], example: [[
'id' => 3,
'code' => 'official',
'name' => 'official',
'type' => 'madong',
'version' => '1.0.0',
'status' => 1,
'description' => '官方应用插件',
'detail_description' => '',
'author' => 'Madong',
'cover' => '',
'poster' => '',
'price' => 0,
'downloads' => 0,
'rating' => 0,
'created_at' => '2026-03-19 16:26:19',
'updated_at' => '2026-03-19 16:26:19',
'update_time' => '',
'update_logs' => [],
'category' => null,
'category_name' => '',
'tags' => [],
'is_new' => 0,
'is_hot' => 0,
'purchased' => 0,
'installed' => 0,
'manual_uninstall' => 0,
'composer_dependencies' => [],
'npm_dependencies' => [],
'is_installed' => 1,
'installed_version' => '1.0.0',
'has_update' => 0,
'is_purchased' => 1,
'is_downloaded' => 1,
'can_uninstall' => 1,
'can_download' => 1,
'undeletable' => 1,
'version_info' => [
'remote' => [
'version' => '1.0.0',
'release_date' => '2026-03-19 16:26:19',
],
'local' => [
'version' => '1.0.0',
'install_date' => '2026-03-19 16:26:19',
],
'comparison' => [
'needs_update' => 0,
'is_latest' => 1,
'version_difference' => null,
],
],
]])]
#[Permission(code: 'plugin:module:list')]
public function index(Request $request): \support\Response
{
try {
$category = $request->input('category', null);
$pageInput = $request->input('current', $request->input('page', 1));
$limitInput = $request->input('size', $request->input('limit', 15));
$page = max(1, (int)$pageInput);
$limit = max(1, (int)$limitInput);
$type = $request->input('type');
$keyword = $request->input('keyword');
/** @var PluginService $service */
$service = Container::make(PluginService::class);
$result = $service->getList($category, $type, $keyword, $page, $limit);
return Json::success('common.operation.success', $result);
} catch (\Throwable $e) {
return Json::fail($e->getMessage(), []);
}
}
#[OA\Get(
path: '/plugin/{name}/download',
summary: '下载模块',
tags: ['模块市场'],
)]
#[OA\Parameter(
name: 'name',
description: '模块标识',
in: 'path',
required: true,
schema: new OA\Schema(type: 'string')
)]
#[SimpleResponse(schema: [], example: [])]
public function download(Request $request): \support\Response
{
try {
$pluginCode = $request->route->param('name');
// 1. 获取下载链接
$remoteService = Container::make(PluginRemoteService::class);
$authCode = config('madong.auth_code');
$secretKey = config('madong.auth_secret');
$downloadInfo = $remoteService->getRemoteDownloadService($authCode, $secretKey, $pluginCode, 'latest');
if (empty($downloadInfo['url'])) {
return Json::fail('获取下载链接失败');
}
// 2. 下载并解压插件
$downloadService = Container::make(PluginDownloadService::class);
$result = $downloadService->downloadAndExtract($pluginCode, $downloadInfo['url']);
return Json::success('下载成功', $result);
} catch (\Throwable $e) {
return Json::fail($e->getMessage());
}
}
#[OA\Get(
path: '/plugin/detail/{name}',
summary: '获取模块详情',
tags: ['模块市场'],
)]
#[OA\Parameter(
name: 'name',
description: '模块标识',
in: 'path',
required: true,
schema: new OA\Schema(type: 'string')
)]
#[SimpleResponse(schema: [], example: [])]
public function detail(Request $request): \support\Response
{
try {
$moduleName = $request->route->param('name');
/** @var PluginService $service */
$service = Container::make(PluginService::class);
$result = $service->getList(null, null, $moduleName);
return Json::success('common.operation.success', $result['items'][0]);
} catch (\Throwable $e) {
return Json::fail($e->getMessage(), []);
}
}
#[OA\Get(
path: '/plugin/{name}/upgrade-logs',
summary: '获取模块升级日志',
tags: ['模块市场'],
)]
#[OA\Parameter(
name: 'name',
description: '模块标识',
in: 'path',
required: true,
schema: new OA\Schema(type: 'string')
)]
#[SimpleResponse(schema: [], example: [])]
public function upgradeLogs(Request $request): \support\Response
{
try {
$moduleName = $request->route->param('name');
/** @var PluginService $service */
$service = Container::make(PluginService::class);
$result = $service->getUpgradeLogs($moduleName);
return Json::success('common.operation.success', $result);
} catch (\Throwable $e) {
return Json::fail($e->getMessage(), []);
}
}
#[OA\Get(
path: '/plugin/check-environment',
summary: '环境检测',
tags: ['模块市场'],
)]
#[OA\Parameter(
name: 'name',
description: '模块标识',
in: 'query',
required: true,
schema: new OA\Schema(type: 'string')
)]
#[SimpleResponse(schema: [], example: [])]
public function checkEnvironment(Request $request): \support\Response
{
try {
$name = $request->input('name');
/** @var PluginInstallService $service */
$service = Container::make(PluginInstallService::class);
$result = $service->installCheck($name);
// 提取路径列表和状态
$paths = [];
foreach ($result['checks'] as $check) {
if (isset($check['path'])) {
// 只展示从madong开始的路径
$path = $check['path'];
$madongPos = strpos(strtolower($path), 'madong');
if ($madongPos !== false) {
// 截取从madong开始的路径
$path = substr($path, $madongPos);
// 确保路径格式正确,madong后面应该有目录分隔符
if (substr($path, 6, 1) !== DIRECTORY_SEPARATOR) {
$path = 'madong' . DIRECTORY_SEPARATOR . substr($path, 6);
}
}
$paths[] = [
'path' => $path,
'requirement' => $check['permission_type'] ?? 'readable',
'status' => $check['status'] === 'success' ? 'success' : 'error',
];
}
}
return Json::success('common.operation.success', [
'paths' => $paths,
'overall_status' => $result['overall_status'],
'message' => $result['message'],
]);
} catch (\Throwable $e) {
return Json::fail($e->getMessage(), []);
}
}
#[OA\Get(
path: '/plugin/install',
summary: '插件安装',
tags: ['模块市场'],
)]
#[SimpleResponse(schema: [], example: [])]
public function install(Request $request): void
{
$connection = $request->connection;
$code = $request->input('code');
$mode = $request->input('mode', 'local');
// 验证参数
if (empty($code)) {
$connection->send(new Response(200, [
'Content-Type' => 'text/event-stream',
'Cache-Control' => 'no-cache',
'Connection' => 'keep-alive',
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Expose-Headers' => 'Content-Type',
], "\r\n"));
$connection->send(\core\tool\Sse::error('参数错误:缺少code参数'));
return;
}
// 发送SSE响应头
$connection->send(new Response(200, [
'Content-Type' => 'text/event-stream',
'Cache-Control' => 'no-cache',
'Connection' => 'keep-alive',
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Expose-Headers' => 'Content-Type',
], "\r\n"));
try {
// 发送开始安装消息
$connection->send(Sse::progress('开始安装插件 ' . $code, 0));
// 调用安装服务
$generator = (new PluginInstallService())->install($code, $mode);
foreach ($generator as $chunk) {
$connection->send($chunk);
}
} catch (\Exception $e) {
// 发送错误消息
$connection->send(Sse::error('安装失败:' . $e->getMessage()));
}
}
#[OA\Get(
path: '/plugin/uninstall',
summary: '插件卸载(SSE流式)',
tags: ['模块市场'],
)]
#[OA\Parameter(
name: 'code',
description: '插件编码',
in: 'query',
required: true,
schema: new OA\Schema(type: 'string')
)]
#[SimpleResponse(schema: [], example: [])]
public function uninstall(Request $request): void
{
$connection = $request->connection;
$code = $request->input('code');
// 验证参数
if (empty($code)) {
$connection->send(new Response(200, [
'Content-Type' => 'text/event-stream',
'Cache-Control' => 'no-cache',
'Connection' => 'keep-alive',
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Expose-Headers' => 'Content-Type',
], "\r\n"));
$connection->send(Sse::error('参数错误:缺少code参数'));
return;
}
// 发送SSE响应头
$connection->send(new Response(200, [
'Content-Type' => 'text/event-stream',
'Cache-Control' => 'no-cache',
'Connection' => 'keep-alive',
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Expose-Headers' => 'Content-Type',
], "\r\n"));
try {
// 调用卸载服务(统一入口)
$generator = (new PluginUninstallService())->uninstall($code);
foreach ($generator as $chunk) {
$connection->send($chunk);
}
} catch (\Exception $e) {
// 发送错误消息
$connection->send(Sse::error('卸载失败:' . $e->getMessage()));
}
}
#[OA\Delete(
path: '/plugin/{name}',
summary: '插件删除',
tags: ['模块市场'],
)]
#[OA\Parameter(
name: 'name',
description: '插件名称',
in: 'path',
required: true,
schema: new OA\Schema(type: 'string')
)]
#[Permission(code: 'plugin:delete')]
#[SimpleResponse(schema: [], example: [])]
public function destroy(Request $request): \support\Response
{
try {
$name = $request->route->param('name');
if (empty($name)) {
return Json::fail('参数错误:缺少name参数', []);
}
/** @var PluginUninstallService $service */
$service = Container::get(PluginUninstallService::class);
$service->delete($name);
return Json::success('common.operation.delete.success', []);
} catch (\Throwable $e) {
return Json::fail($e->getMessage());
}
}
#[OA\Get(
path: '/plugin/select',
summary: '获取已安装插件列表(用于下拉框)',
tags: ['模块市场'],
)]
#[SimpleResponse(schema: [], example: [])]
public function select(Request $request): \support\Response
{
try {
/** @var PluginService $service */
$service = Container::make(PluginService::class);
// 获取本地插件列表(包括已安装和未安装的)
$localModules = $service->getLocalModules();
// 过滤出已安装的插件
$installedPlugins = array_filter($localModules, function ($module) {
return $module['is_installed'] === true && $module['status'] == 1;
});
// 构建下拉框格式数据
$selectItems = [];
foreach ($installedPlugins as $plugin) {
$selectItems[] = [
'value' => $plugin['name'],
'label' => $plugin['name'] . ' - ' . $plugin['description'],
'name' => $plugin['name'],
'description' => $plugin['description'],
'version' => $plugin['version'],
'type' => $plugin['type'] ?? 'plugin',
];
}
return Json::success('common.operation.success', array_values($selectItems));
} catch (\Throwable $e) {
return Json::fail($e->getMessage(), []);
}
}
}
@@ -0,0 +1,301 @@
<?php
declare(strict_types=1);
/**
*+------------------
* madong
*+------------------
* Copyright (c) https://gitee.com/motion-code All rights reserved.
*+------------------
* Author: Mr. April (405784684@qq.com)
*+------------------
* Official Website: http://www.madong.tech
*/
namespace app\adminapi\controller\plugin;
use app\adminapi\controller\Crud;
use app\adminapi\middleware\AccessTokenMiddleware;
use app\adminapi\middleware\OperationMiddleware;
use app\adminapi\middleware\PermissionMiddleware;
use app\adminapi\validate\plugin\PluginValidate;
use app\service\admin\plugin\PluginDevelopService;
use madong\swagger\annotation\response\DataResponse;
use madong\swagger\annotation\response\PageResponse;
use madong\swagger\annotation\response\SimpleResponse;
use madong\swagger\attribute\Permission;
use core\tool\Json;
use OpenApi\Attributes as OA;
use support\annotation\Middleware;
use support\Request;
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
final class PluginDevelopController extends Crud
{
public function __construct(PluginDevelopService $service, PluginValidate $validate)
{
$this->service = $service;
$this->validate = $validate;
}
/**
* 插件列表
* 扫描插件目录,获取type为madong:前缀的插件,同步到数据库并返回列表
*
* @param Request $request
*
* @return \support\Response
*/
#[OA\Get(
path: '/plugin/develop',
summary: '插件列表',
tags: ['插件开发'],
parameters: [
new OA\Parameter(
name: 'page',
description: '页码',
in: 'query',
required: false,
schema: new OA\Schema(type: 'integer', default: 1)
),
new OA\Parameter(
name: 'limit',
description: '每页数量',
in: 'query',
required: false,
schema: new OA\Schema(type: 'integer', default: 15)
),
new OA\Parameter(
name: 'title',
description: '插件标题',
in: 'query',
required: false,
schema: new OA\Schema(type: 'string')
),
new OA\Parameter(
name: 'author',
description: '作者',
in: 'query',
required: false,
schema: new OA\Schema(type: 'string')
),
new OA\Parameter(
name: 'status',
description: '状态',
in: 'query',
required: false,
schema: new OA\Schema(type: 'integer')
),
]
)]
#[Permission(code: 'plugin:develop:list')]
#[PageResponse(schema: [], example: [[
"id" => "2032735331152958596",
"name" => "官网管理",
"icon" => null,
"code" => "official",
"description" => "官网管理插件,用于搭建和管理企业官方网站",
"enabled" => 1,
"author" => "Mr.April",
"version" => "1.0.0",
"cover" => null,
"type" => "madong:plugin",
"support_app" => "admin",
"installed_at" => null,
"created_at" => 1773476844,
"updated_at" => 1773476844,
"variables" => null,
"created_date" => "2026-03-14 16:27:24",
"updated_date" => "2026-03-14 16:27:24",
]])]
public function index(Request $request): \support\Response
{
try {
// 使用标准模式:通过 selectInput 处理查询参数
[$where, , $limit, , , $page] = $this->selectInput($request);
// 调用服务层获取列表数据
$result = $this->service->getList($where, $page, $limit);
// 使用标准格式返回
return Json::success($result);
} catch (\Exception $e) {
return Json::fail($e->getMessage());
}
}
#[OA\Get(
path: '/plugin/develop/{id}',
summary: '插件详情',
tags: ['插件开发'],
parameters: [
new OA\Parameter(
name: 'id',
description: '插件ID',
in: 'path',
required: true,
schema: new OA\Schema(type: 'integer')
),
]
)]
#[Permission(code: 'plugin:develop:read')]
#[DataResponse(schema: [], example: [
"id" => "2032735331152958596",
"title" => "官网管理",
"icon" => null,
"key" => "official",
"desc" => "官网管理插件,用于搭建和管理企业官方网站",
"status" => 1,
"author" => "Mr.April",
"version" => "1.0.0",
"cover" => null,
"type" => "madong:plugin",
"support_app" => "admin",
"installed_at" => null,
"created_at" => 1773476844,
"updated_at" => 1773476844,
"variables" => null,
"created_date" => "2026-03-14 16:27:24",
"updated_date" => "2026-03-14 16:27:24",
])]
public function show(Request $request): \support\Response
{
try {
$id = $request->route->param('id');
$plugin = $this->service->read($id);
if (!$plugin) {
return Json::fail('插件不存在');
}
return Json::success($plugin->toArray());
} catch (\Exception $e) {
return Json::fail($e->getMessage());
}
}
/**
* 创建插件
*
* @param Request $request
*
* @return \support\Response
* @throws \Throwable
*/
#[OA\Post(
path: '/plugin/develop',
summary: '创建插件',
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(
required: ['title', 'key'],
properties: [
new OA\Property(property: 'title', description: '插件标题', type: 'string'),
new OA\Property(property: 'key', description: '插件标识(唯一值)', type: 'string'),
new OA\Property(property: 'desc', description: '插件描述', type: 'string'),
new OA\Property(property: 'author', description: '作者', type: 'string'),
new OA\Property(property: 'version', description: '版本', type: 'string', default: '1.0.0'),
new OA\Property(property: 'type', description: '类型', type: 'string', default: 'madong:plugin'),
new OA\Property(property: 'icon', description: '图标(base64)', type: 'string'),
new OA\Property(property: 'cover', description: '封面(base64)', type: 'string'),
new OA\Property(property: 'frontend_type', description: '前端类型', type: 'string', default: 'admin'),
]
)
),
tags: ['插件开发']
)]
#[Permission(code: 'plugin:develop:create')]
#[SimpleResponse(schema: [], example: [])]
public function store(Request $request): \support\Response
{
try {
$this->validate->scene('store')->check($request->all());
$this->service->store($request->all());
return Json::success();
} catch (\Exception $e) {
return Json::fail($e->getMessage());
}
}
/**
* 打包插件
* 将后端、后台前端、前台前端复制到后端server/plugin/xxx/resource目录,并打包为zip
*
* @param Request $request
*
* @return \support\Response
*/
#[OA\Post(
path: '/plugin/develop/build',
summary: '打包插件',
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(
required: ['plugin_key'],
properties: [
new OA\Property(property: 'plugin_key', description: '插件标识', type: 'string'),
]
)
),
tags: ['插件开发']
)]
#[Permission(code: 'plugin:develop:build')]
#[SimpleResponse(schema: [], example: [
"plugin_key" => "test",
"zip_path" => "D:\\MyProject\\private\\madong/server/runtime/adminapi/test.zip",
"has_frontend" => false,
])]
public function build(Request $request): \support\Response
{
try {
$pluginKey = $request->input('plugin_key');
if (empty($pluginKey)) {
return Json::fail('插件标识不能为空');
}
$result = $this->service->buildPlugin($pluginKey);
return Json::success('插件打包成功',$result);
} catch (\Exception $e) {
return Json::fail($e->getMessage());
}
}
#[OA\Put(
path: '/plugin/develop/{id}',
summary: '编辑插件',
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(
properties: [
new OA\Property(property: 'title', description: '插件标题', type: 'string'),
new OA\Property(property: 'desc', description: '插件描述', type: 'string'),
new OA\Property(property: 'author', description: '作者', type: 'string'),
new OA\Property(property: 'version', description: '版本', type: 'string'),
new OA\Property(property: 'icon', description: '图标(base64)', type: 'string'),
new OA\Property(property: 'cover', description: '封面(base64)', type: 'string'),
]
)
),
tags: ['插件开发'],
parameters: [
new OA\Parameter(
name: 'id',
description: '插件ID',
in: 'path',
required: true,
schema: new OA\Schema(type: 'integer')
),
]
)]
#[Permission(code: 'plugin:develop:update')]
#[SimpleResponse(schema: [], example: [])]
public function update(Request $request): \support\Response
{
try {
$id = $request->route->param('id');
$this->service->update($id, $request->all());
return Json::success('更新成功');
} catch (\Throwable $e) {
return Json::fail($e->getMessage());
}
}
}
@@ -0,0 +1,118 @@
<?php
declare(strict_types=1);
/**
*+------------------
* madong
*+------------------
* Copyright (c) https://gitee.com/motion-code All rights reserved.
*+------------------
* Author: Mr. April (405784684@qq.com)
*+------------------
* Official Website: http://www.madong.tech
*/
namespace app\adminapi\controller\plugin;
use app\adminapi\controller\Base;
use app\adminapi\middleware\AccessTokenMiddleware;
use app\adminapi\middleware\OperationMiddleware;
use app\adminapi\middleware\PermissionMiddleware;
use app\service\core\plugin\PluginRemoteService;
use core\tool\Json;
use madong\swagger\annotation\auth\AllowAnonymous;
use madong\swagger\annotation\response\SimpleResponse;
use madong\swagger\attribute\Permission;
use OpenApi\Attributes as OA;
use support\annotation\Middleware;
use support\Request;
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
final class PluginMadongAuthController extends Base
{
public function __construct(PluginRemoteService $service)
{
$this->service = $service;
}
#[OA\Get(
path: '/madong/auth-info',
summary: '获取插件授权信息',
tags: ['应用授权']
)]
#[Permission('madong:delegation:read')]
#[AllowAnonymous(requireToken: true, requirePermission: true)]
#[SimpleResponse(example: '{"code": 0,"msg": "ok","data": {"company_name": "-","domain": "-","auth_code": "202601***********888888"}}')]
public function read(Request $request): \support\Response
{
$data = [
'company_name' => '-',
'domain' => '-',
'auth_code' => config('madong.auth_code'),
];
return Json::success($data);
}
#[OA\Post(
path: '/madong/auth-info',
summary: '设置插件授权信息',
tags: ['应用授权']
)]
#[Permission('madong:delegation:setting')]
#[SimpleResponse(schema: [], example: [])]
public function store(Request $request): \support\Response
{
try {
$param = $request->all();
if (empty($param['auth_code'])) {
throw new \Exception('auth_code 不能为空');
}
if (empty($param['auth_secret'])) {
throw new \Exception('auth_secret 不能为空');
}
$this->service->verifyRemoteAuthorization($param['auth_code'],$param['auth_secret']);
//追加到系统配置
$this->updateMadongConfig($param['auth_code'], $param['auth_secret']);
return Json::success('授权设置成功');
} catch (\Throwable $e) {
return Json::fail($e->getMessage());
}
}
/**
* 更新server/config/madong.php文件中的配置
*
* @param string $authCode 授权码
* @param string $authSecret 授权密钥
*
* @throws \Exception
*/
private function updateMadongConfig(string $authCode, string $authSecret): void
{
$configPath = base_path() . '/config/madong.php';
if (!file_exists($configPath)) {
throw new \Exception('madong.php配置文件不存在');
}
$configContent = file_get_contents($configPath);
// 定义需要替换的参数映射
$replacements = [
'auth_code' => $authCode,
'auth_secret' => $authSecret,
];
foreach ($replacements as $key => $value) {
$pattern = '/\'' . $key . '\'\s*=>\s*env\(\'madong\..*?\'\s*,\s*\'(.*?)\'\)/';
$replacement = "'$key' => env('madong." . ($key === 'auth_code' ? 'code' : 'secret') . "', '$value')";
$configContent = preg_replace($pattern, $replacement, $configContent);
}
file_put_contents($configPath, $configContent);
}
}