✨ 改进组配置,修复bug
This commit is contained in:
@@ -31,9 +31,6 @@ final class ConfigKey
|
||||
/** @var string 账户是否需要验证 */
|
||||
const IsUserNeedVerify = 'is_user_need_verify';
|
||||
|
||||
/** @var string 是否启用缩略图功能 */
|
||||
const IsEnableThumbnail = 'is_enable_thumbnail';
|
||||
|
||||
/** @var string 邮件配置 */
|
||||
const MailConfigs = 'mail_configs';
|
||||
|
||||
|
||||
@@ -11,7 +11,16 @@ final class GroupConfigKey
|
||||
const ConcurrentUploadNum = 'concurrent_upload_num';
|
||||
|
||||
/** @var string 上传是否需要审查 */
|
||||
const IsUploadNeedsReview = 'is_upload_needs_review';
|
||||
const IsEnableReview = 'is_enable_review';
|
||||
|
||||
/** @var string 是否启用原图保护功能 */
|
||||
const IsEnableOriginalProtection = 'is_enable_original_protection';
|
||||
|
||||
/** @var string 上传是否启用水印功能 */
|
||||
const IsEnableWatermark = 'is_enable_watermark';
|
||||
|
||||
/** @var string 水印配置 */
|
||||
const WatermarkConfigs = 'watermark_configs';
|
||||
|
||||
/** @var string 每分钟上传限制 */
|
||||
const LimitPerMinute = 'limit_per_minute';
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
final class GroupWatermarkConfigKey
|
||||
{
|
||||
|
||||
}
|
||||
@@ -15,7 +15,4 @@ final class KodoOption
|
||||
|
||||
/** @var string Bucket */
|
||||
const Bucket = 'bucket';
|
||||
|
||||
/** @var string 是否启用获取原始 url 功能 */
|
||||
const IsEnableOriginalProtection = 'is_enable_origin_url';
|
||||
}
|
||||
|
||||
@@ -9,7 +9,4 @@ final class LocalOption
|
||||
|
||||
/** @var string 根目录 */
|
||||
const Root = 'root';
|
||||
|
||||
/** @var string 是否启用原图保护功能 */
|
||||
const IsEnableOriginalProtection = 'is_enable_original_protection';
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use App\Enums\GroupConfigKey;
|
||||
use App\Enums\ImagePermission;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ImageRenameRequest;
|
||||
@@ -30,7 +31,7 @@ class ImageController extends Controller
|
||||
/** @var User $user */
|
||||
$user = Auth::user();
|
||||
|
||||
$images = Image::with('strategy')
|
||||
$images = Image::with('group')
|
||||
->where('user_id', $user->id)
|
||||
->when($request->query('order') ?: 'newest', function (Builder $builder, $order) {
|
||||
switch ($order) {
|
||||
@@ -93,14 +94,23 @@ class ImageController extends Controller
|
||||
{
|
||||
/** @var Image $image */
|
||||
$image = Image::query()
|
||||
->with('group')
|
||||
->where('key', $request->route('key'))
|
||||
->where('extension', $request->route('extension'))
|
||||
->firstOr(fn() => abort(404));
|
||||
if (! $image->group->configs->get(GroupConfigKey::IsEnableOriginalProtection)) {
|
||||
abort(404);
|
||||
}
|
||||
try {
|
||||
$contents = $image->filesystem()->read($image->pathname);
|
||||
} catch (FilesystemException $e) {
|
||||
abort(404);
|
||||
}
|
||||
// 是否启用了水印功能
|
||||
if ($image->group->configs->get(GroupConfigKey::IsEnableWatermark)) {
|
||||
// GroupConfigKey::WatermarkConfigs
|
||||
// TODO 动态生成水印并缓存
|
||||
}
|
||||
return \response()->stream(function () use ($contents) {
|
||||
echo $contents;
|
||||
}, headers: ['Content-type' => $image->mimetype]);
|
||||
|
||||
+3
-13
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\ConfigKey;
|
||||
use App\Enums\GroupConfigKey;
|
||||
use App\Utils;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@@ -41,19 +43,7 @@ class Group extends Model
|
||||
*/
|
||||
public static function getDefaultConfigs(): Collection
|
||||
{
|
||||
return collect([
|
||||
GroupConfigKey::MaximumFileSize => 5120,
|
||||
GroupConfigKey::ConcurrentUploadNum => 3,
|
||||
GroupConfigKey::IsUploadNeedsReview => false,
|
||||
GroupConfigKey::LimitPerMinute => 20,
|
||||
GroupConfigKey::LimitPerHour => 100,
|
||||
GroupConfigKey::LimitPerDay => 300,
|
||||
GroupConfigKey::LimitPerWeek => 600,
|
||||
GroupConfigKey::LimitPerMonth => 999,
|
||||
GroupConfigKey::AcceptedFileSuffixes => ['jpg', 'jpeg', 'gif', 'png', 'apng', 'bmp', 'ico'],
|
||||
GroupConfigKey::PathNamingRule => '{Y}/{m}/{d}',
|
||||
GroupConfigKey::FileNamingRule => '{uniqid}',
|
||||
]);
|
||||
return Utils::config(ConfigKey::GuestGroupConfigs);
|
||||
}
|
||||
|
||||
protected static function booted()
|
||||
|
||||
+19
-3
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\GroupConfigKey;
|
||||
use App\Enums\Strategy\LocalOption;
|
||||
use App\Enums\StrategyKey;
|
||||
use App\Service\ImageService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
@@ -18,6 +20,7 @@ use League\Flysystem\Filesystem;
|
||||
* @property int $id
|
||||
* @property int $user_id
|
||||
* @property int $album_id
|
||||
* @property int $group_id
|
||||
* @property int $strategy_id
|
||||
* @property string $key
|
||||
* @property string $path
|
||||
@@ -43,6 +46,7 @@ use League\Flysystem\Filesystem;
|
||||
* @property Carbon $created_at
|
||||
* @property-read User $user
|
||||
* @property-read Album $album
|
||||
* @property-read Group $group
|
||||
* @property-read Strategy $strategy
|
||||
*/
|
||||
class Image extends Model
|
||||
@@ -70,6 +74,7 @@ class Image extends Model
|
||||
protected $hidden = [
|
||||
'user_id',
|
||||
'album_id',
|
||||
'group_id',
|
||||
'strategy_id',
|
||||
'is_unhealthy',
|
||||
'permission',
|
||||
@@ -120,10 +125,10 @@ class Image extends Model
|
||||
return Storage::disk('uploads')->url($this->pathname);
|
||||
}
|
||||
// 是否启用原图保护功能
|
||||
if ($this->strategy->configs->get(LocalOption::IsEnableOriginalProtection)) {
|
||||
if ($this->group->configs->get(GroupConfigKey::IsEnableOriginalProtection)) {
|
||||
return asset("{$this->key}.{$this->extension}");
|
||||
} else {
|
||||
return rtrim($this->strategy->configs->get(LocalOption::Domain), '/').'/'.$this->pathname;
|
||||
return rtrim($this->strategy->configs->get('domain'), '/').'/'.$this->pathname;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -162,9 +167,20 @@ class Image extends Model
|
||||
return $this->belongsTo(Album::class, 'album_id', 'id');
|
||||
}
|
||||
|
||||
public function group(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Group::class, 'group_id', 'id')->withDefault(function (Group $group) {
|
||||
$group->name = '系统默认组';
|
||||
$group->configs = $group::getDefaultConfigs();
|
||||
});
|
||||
}
|
||||
|
||||
public function strategy(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Strategy::class, 'strategy_id', 'id');
|
||||
return $this->belongsTo(Strategy::class, 'strategy_id', 'id')->withDefault(function (Strategy $strategy) {
|
||||
$strategy->key = StrategyKey::Local;
|
||||
$strategy->configs = collect([LocalOption::Root => config('filesystems.disks.uploads.root')]);
|
||||
});
|
||||
}
|
||||
|
||||
private function generateKey($length = 6): string
|
||||
|
||||
@@ -51,7 +51,6 @@ class Strategy extends Model
|
||||
static::creating(function (self $strategy) {
|
||||
$strategy->configs = collect([
|
||||
LocalOption::Domain => env('APP_URL'),
|
||||
LocalOption::IsEnableOriginalProtection => true,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,11 +24,15 @@ use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Intervention\Image\Facades\Image as InterventionImage;
|
||||
use Intervention\Image\Gd\Font;
|
||||
use Intervention\Image\ImageManager;
|
||||
use JetBrains\PhpStorm\NoReturn;
|
||||
use League\Flysystem\Filesystem;
|
||||
use League\Flysystem\FilesystemAdapter;
|
||||
use League\Flysystem\FilesystemException;
|
||||
use League\Flysystem\Local\LocalFilesystemAdapter;
|
||||
use Overtrue\Flysystem\Qiniu\QiniuAdapter;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
class ImageService
|
||||
{
|
||||
@@ -68,6 +72,7 @@ class ImageService
|
||||
|
||||
// 如果该用户有角色组,覆盖默认组、上传策略配置
|
||||
if ($user->group) {
|
||||
$image->group_id = $user->group_id;
|
||||
$configs = $user->group->configs;
|
||||
// 获取策略列表,根据用户所选的策略上传
|
||||
$strategies = $user->group->strategies()->get();
|
||||
@@ -155,15 +160,13 @@ class ImageService
|
||||
$builder->where('strategy_id', $id);
|
||||
})->where('md5', $image->md5)->where('sha1', $image->sha1)->first();
|
||||
if (is_null($existing)) {
|
||||
$handle = fopen($file, 'r');
|
||||
$handle = $img->stream();
|
||||
try {
|
||||
$filesystem->writeStream($pathname, $handle);
|
||||
$filesystem->writeStream($pathname, $handle->detach());
|
||||
} catch (FilesystemException $e) {
|
||||
throw new UploadException('图片上传失败');
|
||||
}
|
||||
if (! fclose($handle)) {
|
||||
throw new UploadException('资源关闭失败');
|
||||
}
|
||||
$handle->close();
|
||||
} else {
|
||||
$image->fill($existing->only('path', 'name'));
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ class Utils
|
||||
case ConfigKey::IsEnableGallery:
|
||||
case ConfigKey::IsEnableRegistration:
|
||||
case ConfigKey::IsUserNeedVerify:
|
||||
case ConfigKey::IsEnableThumbnail:
|
||||
$value = (bool) $value;
|
||||
break;
|
||||
case ConfigKey::MailConfigs:
|
||||
|
||||
+2
-1
@@ -13,7 +13,8 @@
|
||||
"laravel/framework": "^9.0",
|
||||
"laravel/sanctum": "^2.14",
|
||||
"laravel/tinker": "^2.7",
|
||||
"overtrue/flysystem-qiniu": "^2.0"
|
||||
"overtrue/flysystem-qiniu": "^2.0",
|
||||
"topthink/think-image": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.6",
|
||||
|
||||
Generated
+51
-1
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c36bb3f58e9cf016cf72e03a16057222",
|
||||
"content-hash": "afa63033085cb52b18c21975da51c685",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asm89/stack-cors",
|
||||
@@ -5577,6 +5577,56 @@
|
||||
},
|
||||
"time": "2021-12-08T09:12:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "topthink/think-image",
|
||||
"version": "v1.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/top-think/think-image.git",
|
||||
"reference": "8586cf47f117481c6d415b20f7dedf62e79d5512"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/top-think/think-image/zipball/8586cf47f117481c6d415b20f7dedf62e79d5512",
|
||||
"reference": "8586cf47f117481c6d415b20f7dedf62e79d5512",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"ext-gd": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.8.*",
|
||||
"topthink/framework": "^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"think\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "yunwuxin",
|
||||
"email": "448901948@qq.com"
|
||||
}
|
||||
],
|
||||
"description": "The ThinkPHP5 Image Package",
|
||||
"support": {
|
||||
"issues": "https://github.com/top-think/think-image/issues",
|
||||
"source": "https://github.com/top-think/think-image/tree/master"
|
||||
},
|
||||
"time": "2016-09-29T06:05:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
"version": "v5.4.1",
|
||||
|
||||
@@ -21,6 +21,7 @@ class CreateImagesTable extends Migration
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->nullable()->comment('用户')->constrained('users')->onDelete('set null');
|
||||
$table->foreignId('album_id')->nullable()->comment('相册')->constrained('albums')->onDelete('set null');
|
||||
$table->foreignId('group_id')->nullable()->comment('角色组')->constrained('groups')->onDelete('set null');
|
||||
$table->foreignId('strategy_id')->nullable()->comment('策略')->constrained('strategies')->onDelete('set null');
|
||||
$table->string('key')->unique()->comment('key');
|
||||
$table->string('path')->comment('保存路径');
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\ConfigKey;
|
||||
use App\Enums\GroupConfigKey;
|
||||
use App\Enums\Mail\SmtpOption;
|
||||
use App\Models\Group;
|
||||
use Illuminate\Database\Seeder;
|
||||
@@ -29,7 +30,6 @@ class DatabaseSeeder extends Seeder
|
||||
ConfigKey::IsAllowGuestUpload => 1,
|
||||
ConfigKey::UserInitialCapacity => 512000,
|
||||
ConfigKey::IsUserNeedVerify => 1,
|
||||
ConfigKey::IsEnableThumbnail => 1,
|
||||
ConfigKey::MailConfigs => json_encode([
|
||||
'default' => 'smtp',
|
||||
'mailers' => [
|
||||
@@ -42,7 +42,22 @@ class DatabaseSeeder extends Seeder
|
||||
SmtpOption::AuthMode => null,
|
||||
],
|
||||
]),
|
||||
ConfigKey::GuestGroupConfigs => Group::getDefaultConfigs()->toJson(),
|
||||
ConfigKey::GuestGroupConfigs => collect([
|
||||
GroupConfigKey::MaximumFileSize => 5120,
|
||||
GroupConfigKey::ConcurrentUploadNum => 3,
|
||||
GroupConfigKey::IsEnableReview => false,
|
||||
GroupConfigKey::IsEnableWatermark => false,
|
||||
GroupConfigKey::IsEnableOriginalProtection => false,
|
||||
GroupConfigKey::WatermarkConfigs => new \stdClass(),
|
||||
GroupConfigKey::LimitPerMinute => 20,
|
||||
GroupConfigKey::LimitPerHour => 100,
|
||||
GroupConfigKey::LimitPerDay => 300,
|
||||
GroupConfigKey::LimitPerWeek => 600,
|
||||
GroupConfigKey::LimitPerMonth => 999,
|
||||
GroupConfigKey::AcceptedFileSuffixes => ['jpg', 'jpeg', 'gif', 'png', 'apng', 'bmp', 'ico'],
|
||||
GroupConfigKey::PathNamingRule => '{Y}/{m}/{d}',
|
||||
GroupConfigKey::FileNamingRule => '{uniqid}',
|
||||
])->toJson(),
|
||||
])->transform(function ($value, $key) use ($date) {
|
||||
return ['name' => $key, 'value' => $value, 'updated_at' => $date, 'created_at' => $date];
|
||||
})->values()->toArray();
|
||||
|
||||
@@ -723,7 +723,7 @@
|
||||
},
|
||||
open: {
|
||||
text: '新窗口打开',
|
||||
action: e => window.open($(e).find('img').attr('src')),
|
||||
action: e => window.open($(e).data('json').url),
|
||||
visible: () => ds.getSelection().length === 1,
|
||||
},
|
||||
copies: {
|
||||
|
||||
Reference in New Issue
Block a user