Skip to content

Commit

Permalink
feat: ueditor plus upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
modstart committed Jul 8, 2024
1 parent 2e9780f commit 01de89b
Show file tree
Hide file tree
Showing 228 changed files with 32,844 additions and 66 deletions.
6 changes: 3 additions & 3 deletions config/module.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@
'Cms' => [
'enable' => true,
],
// 'DataAliyunOssFe' => [
// 'enable' => true,
// ],
'DataAliyunOssFe' => [
'enable' => true,
],
// 'Recommend' => [
// 'enable' => true,
// ],
Expand Down
126 changes: 126 additions & 0 deletions module/DataAliyunOssFe/Admin/Controller/ConfigController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php

namespace Module\DataAliyunOssFe\Admin\Controller;

use Illuminate\Routing\Controller;
use ModStart\Admin\Layout\AdminConfigBuilder;
use ModStart\Support\Concern\HasFields;

class ConfigController extends Controller
{
public function index(AdminConfigBuilder $builder)
{
$builder->pageTitle('阿里云OSS存储(前端直传)');
/** @var HasFields $builder */
$builder->layoutPanel('公共配置', function ($builder) {
/** @var HasFields $builder */
$builder->switch('DataAliyunOssFe_Enable', '启用');
$builder->select('DataAliyunOssFe_Region', '地区')
->options([
'cn-hangzhou' => '华东1(杭州)',
'cn-shanghai' => '华东2(上海)',
'cn-qingdao' => '华北1(青岛)',
'cn-beijing' => '华北2(北京)',
'cn-zhangjiakou' => '华北3(张家口)',
'cn-huhehaote' => '华北5(呼和浩特)',
'cn-shenzhen' => '华南1(深圳)',
'cn-hongkong' => '中国(香港)',
'ap-southeast-1' => '亚太东南1(新加坡)',
'ap-southeast-2' => '亚太东南2(悉尼)',
'ap-southeast-3' => '亚太东南3(吉隆坡)',
'ap-southeast-5' => '亚太东南5(雅加达)',
'ap-south-1' => '亚太南部1(孟买)',
'ap-northeast-1' => '亚太东北1(东京)',
'ap-northeast-2' => '亚太东北2(首尔)',
'ap-south-1' => '亚太南部1(孟买)',
'eu-central-1' => '欧洲中部1(法兰克福)',
'eu-west-1' => '欧洲西部1(伦敦)',
'me-east-1' => '中东东部1(迪拜)',
'us-west-1' => '美国西部1(硅谷)',
'us-east-1' => '美国东部1(弗吉尼亚)',
'ap-northeast-1' => '亚太东北1(东京)',
'ap-southeast-1' => '亚太东南1(新加坡)',
'ap-southeast-2' => '亚太东南2(悉尼)',
]);
$builder->text('DataAliyunOssFe_Bucket', 'Bucket');
$builder->text('DataAliyunOssFe_Endpoint', 'Endpoint')
->help('格式为 oss-cn-xxx.aliyuncs.com');
$builder->text('DataAliyunOssFe_Domain', 'Bucket域名')
->help('如果您的OSS开启了CDN加速,可直接配置CDN域名(如 http://xxx.oss-cn-xxx.aliyuncs.com)')
->ruleUrl();
});

$builder->layoutPanel('服务端配置', function ($builder) {
/** @var HasFields $builder */

$builder->html('', '配置说明')->htmlContentFromMarkdown(
'
**用于 OSS 文件的增删改查管理**
需要开通 OSS 上传权限,权限策略参考内容如下:
```
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"oss:Get*",
"oss:Put*",
"oss:DeleteObject"
],
"Resource": [
"acs:oss:*:*:test-oss",
"acs:oss:*:*:test-oss/*"
]
}
]
}
```
'
);
$builder->text('DataAliyunOssFe_AccessKeyId', 'AccessKeyId');
$builder->text('DataAliyunOssFe_AccessKeySecret', 'AccessKeySecret');
});

$builder->layoutPanel('前端配置', function ($builder) {
/** @var HasFields $builder */
$builder->html('', '账号说明')->htmlContentFromMarkdown(
'
**用户前端受限的上传权限**
需要开通
① OSS 上传权限,权限策略参考内容如下:
```json
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": "oss:PutObject",
"Resource": "acs:oss:*:*:test-oss/data_temp/*"
}
]
}
```
② STS 服务权限
需要开通 AliyunSTSAssumeRoleAccess 系统策略。
'
);
$builder->text('DataAliyunOssFe_Front_AccessKeyId', 'AccessKeyId');
$builder->text('DataAliyunOssFe_Front_AccessKeySecret', 'AccessKeySecret');
$builder->text('DataAliyunOssFe_Front_StsEndpoint', 'StsEndpoint')
->help('例如 sts.cn-shanghai.aliyuncs.com ,查看对应地区 <a target="_blank" href="https://help.aliyun.com/zh/ram/developer-reference/api-sts-2015-04-01-endpoint">Endpoint</a>');
$builder->text('DataAliyunOssFe_Front_RoleArn', 'RoleArn')
->help('例如 acs:ram::148316xxxxxxxxx:role/ms-oss-test-fe');
});

$builder->formClass('wide');
return $builder->perform();
}
}
6 changes: 6 additions & 0 deletions module/DataAliyunOssFe/Admin/routes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

/* @var \Illuminate\Routing\Router $router */

$router->match(['get', 'post'], 'data_aliyun_oss_fe/config', 'ConfigController@index');

225 changes: 225 additions & 0 deletions module/DataAliyunOssFe/Core/DataAliyunOssFeDataStorage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
<?php


namespace Module\DataAliyunOssFe\Core;

use AlibabaCloud\SDK\Sts\V20150401\Models\AssumeRoleRequest;
use AlibabaCloud\SDK\Sts\V20150401\Sts;
use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;
use Darabonba\OpenApi\Models\Config;
use Illuminate\Support\Facades\Cache;
use ModStart\Core\Exception\BizException;
use ModStart\Core\Input\Response;
use ModStart\Core\Util\PathUtil;
use ModStart\Data\AbstractDataStorage;
use ModStart\Data\Event\DataFileUploadedEvent;
use Module\DataAliyunOssFe\Util\DataAliyunOssFeUtil;
use OSS\Core\OssException;
use OSS\OssClient;

class DataAliyunOssFeDataStorage extends AbstractDataStorage
{
/**
* @var OssClient
*/
private $client;
private $bucket;

public function init()
{
DataAliyunOssFeUtil::init();
$this->client = new OssClient(
$this->option['accessKeyId'],
$this->option['accessKeySecret'],
$this->option['endpoint']
);
$this->bucket = $this->option['bucket'];
}

public function driverName()
{
return 'AliyunOss';
}


public function has($file)
{
try {
$ret = $this->client->getObjectMeta($this->bucket, $file);
if (empty($ret['etag'])) {
return false;
}
return true;
} catch (\Exception $e) {
return false;
}
}

public function move($from, $to)
{
try {
$this->client->copyObject($this->bucket, $from, $this->bucket, $to);
} catch (OssException $e) {
if (str_contains($e->getMessage(), 'NoSuchKey')) {
} else {
throw $e;
}
}
try {
$this->client->deleteObject($this->bucket, $from);
} catch (\Exception $e) {
if (str_contains($e->getMessage(), 'NoSuchKey')) {
} else {
throw $e;
}
}
}

public function delete($file)
{
try {
$ret = $this->client->deleteObject($this->bucket, $file);
} catch (\Exception $e) {
if (str_contains($e->getMessage(), 'NoSuchKey')) {
} else {
throw $e;
}
}
}

public function put($file, $content)
{
$this->client->putObject($this->bucket, $file, $content);
}

public function get($file)
{
return $this->client->getObject($this->bucket, $file);
}

public function size($file)
{
try {
$ret = $this->client->getObjectMeta($this->bucket, $file);
return intval($ret['content-length']);
} catch (\Exception $e) {
return 0;
}
}

public function getUploadConfig()
{
return Cache::remember('DataAliyunOssFe:Config', 30, function () {
DataAliyunOssFeUtil::init();
$bucket = modstart_config('DataAliyunOssFe_Bucket');
$config = new Config([
"accessKeyId" => modstart_config('DataAliyunOssFe_Front_AccessKeyId'),
"accessKeySecret" => modstart_config('DataAliyunOssFe_Front_AccessKeySecret'),
]);

$config->endpoint = modstart_config('DataAliyunOssFe_Front_StsEndpoint');
$client = new Sts($config);

$assumeRoleRequest = new AssumeRoleRequest([
// roleArn填写步骤2获取的角色ARN
"roleArn" => modstart_config('DataAliyunOssFe_Front_RoleArn'),
// roleSessionName用于自定义角色会话名称,用来区分不同的令牌,例如填写为sessiontest。
"roleSessionName" => "upload-to-data-temp",
// durationSeconds用于设置临时访问凭证有效时间单位为秒,最小值为900,最大值以当前角色设定的最大会话时间为准。本示例指定有效时间为3000秒。
"durationSeconds" => 3600,
// policy填写自定义权限策略,用于进一步限制STS临时访问凭证的权限。
// 如果不指定Policy,则返回的STS临时访问凭证默认拥有指定角色的所有权限。
// 临时访问凭证最后获得的权限是步骤4设置的角色权限和该Policy设置权限的交集。
"policy" => '{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": "oss:PutObject",
"Resource": "acs:oss:*:*:' . $bucket . '/data_temp/*"
}
]
}',
]);
$runtime = new RuntimeOptions([]);
$result = $client->assumeRoleWithOptions($assumeRoleRequest, $runtime);
return [
'region' => 'oss-' . modstart_config('DataAliyunOssFe_Region'),
'bucket' => $bucket,
'accessKeyId' => $result->body->credentials->accessKeyId,
'accessKeySecret' => $result->body->credentials->accessKeySecret,
'securityToken' => $result->body->credentials->securityToken,
'expiration' => $result->body->credentials->expiration,
];
});
}

public function multiPartInit($param)
{
$token = $this->multiPartInitToken($param);
$this->uploadChunkTokenAndUpdateToken($token);
$token['uploadConfig'] = $this->getUploadConfig();
return Response::generateSuccessData($token);
}

public function multiPartUploadEnd($param)
{
$category = $param['category'];
$token = $this->multiPartInitToken($param);
BizException::throwsIfEmpty('DataAliyunOssFe.TokenEmpty', $token);
DataFileUploadedEvent::fire('AliyunOss', $category, $token['fullPath'], isset($param['eventOpt']) ? $param['eventOpt'] : []);
$dataTemp = $this->repository->addTemp($category, $token['path'], $token['name'], $token['size'], empty($token['md5']) ? null : $token['md5']);
$data['data'] = $dataTemp;
$data['path'] = $token['fullPath'];
$data['preview'] = $this->getDriverFullPath($token['fullPath']);
$data['finished'] = true;
$this->uploadChunkTokenAndDeleteToken($token);
return Response::generateSuccessData($data);
}

public function domain()
{
return modstart_config()->getWithEnv('DataAliyunOssFe_Domain');
}

public function domainInternal()
{
return modstart_config()->getWithEnv('DataAliyunOssFe_DomainInternal', modstart_config()->getWithEnv('DataAliyunOssFe_Domain'));
}


public function updateDriverDomain($data)
{
$update = [
'driver' => 'AliyunOss',
'domain' => $this->domain(),
];
$this->repository->updateData($data['id'], $update);
return array_merge($data, $update);
}

public function getDriverFullPath($path)
{
$path = parent::getDriverFullPath($path);
if (PathUtil::isPublicNetPath($path)) {
return $path;
}
return $this->domain() . $path;
}

/**
* @param $path
* @return mixed|string
* @deprecated delete at 2024-04-25
*/
public function getDriverFullPathInternal($path)
{
$path = parent::getDriverFullPathInternal($path);
if (PathUtil::isPublicNetPath($path)) {
return $path;
}
return $this->domainInternal() . $path;
}


}
Loading

0 comments on commit 01de89b

Please sign in to comment.