mirror of
https://github.com/flarum/core.git
synced 2025-08-03 23:17:43 +02:00
Simplify uploads, inject filesystem instances
This avoids injecting the Application god class and assembling default file locations in multiple places. In addition, we no longer use the `MountManager` for these uploads. It only added complexity (by moving tmp files around) and will not be available in the next major release of Flysystem. Note: Passing PSR upload streams to Intervention Image requires an explicit upgrade of the library. (Very likely, users have already updated to the newer versions, as the old constraint allowed it, but we should be explicit for correctness' sake.)
This commit is contained in:
@@ -56,7 +56,7 @@
|
|||||||
"illuminate/support": "5.7.*",
|
"illuminate/support": "5.7.*",
|
||||||
"illuminate/validation": "5.7.*",
|
"illuminate/validation": "5.7.*",
|
||||||
"illuminate/view": "5.7.*",
|
"illuminate/view": "5.7.*",
|
||||||
"intervention/image": "^2.3.0",
|
"intervention/image": "^2.5.0",
|
||||||
"laminas/laminas-diactoros": "^1.8.4",
|
"laminas/laminas-diactoros": "^1.8.4",
|
||||||
"laminas/laminas-httphandlerrunner": "^1.0",
|
"laminas/laminas-httphandlerrunner": "^1.0",
|
||||||
"laminas/laminas-stratigility": "^3.0",
|
"laminas/laminas-stratigility": "^3.0",
|
||||||
|
@@ -9,12 +9,10 @@
|
|||||||
|
|
||||||
namespace Flarum\Api\Controller;
|
namespace Flarum\Api\Controller;
|
||||||
|
|
||||||
use Flarum\Foundation\Application;
|
|
||||||
use Flarum\Settings\SettingsRepositoryInterface;
|
use Flarum\Settings\SettingsRepositoryInterface;
|
||||||
use Flarum\User\AssertPermissionTrait;
|
use Flarum\User\AssertPermissionTrait;
|
||||||
use Laminas\Diactoros\Response\EmptyResponse;
|
use Laminas\Diactoros\Response\EmptyResponse;
|
||||||
use League\Flysystem\Adapter\Local;
|
use League\Flysystem\FilesystemInterface;
|
||||||
use League\Flysystem\Filesystem;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
|
||||||
class DeleteFaviconController extends AbstractDeleteController
|
class DeleteFaviconController extends AbstractDeleteController
|
||||||
@@ -27,17 +25,18 @@ class DeleteFaviconController extends AbstractDeleteController
|
|||||||
protected $settings;
|
protected $settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Application
|
* @var FilesystemInterface
|
||||||
*/
|
*/
|
||||||
protected $app;
|
protected $uploadDir;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param SettingsRepositoryInterface $settings
|
* @param SettingsRepositoryInterface $settings
|
||||||
|
* @param FilesystemInterface $uploadDir
|
||||||
*/
|
*/
|
||||||
public function __construct(SettingsRepositoryInterface $settings, Application $app)
|
public function __construct(SettingsRepositoryInterface $settings, FilesystemInterface $uploadDir)
|
||||||
{
|
{
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->app = $app;
|
$this->uploadDir = $uploadDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,10 +50,8 @@ class DeleteFaviconController extends AbstractDeleteController
|
|||||||
|
|
||||||
$this->settings->set('favicon_path', null);
|
$this->settings->set('favicon_path', null);
|
||||||
|
|
||||||
$uploadDir = new Filesystem(new Local($this->app->publicPath().'/assets'));
|
if ($this->uploadDir->has($path)) {
|
||||||
|
$this->uploadDir->delete($path);
|
||||||
if ($uploadDir->has($path)) {
|
|
||||||
$uploadDir->delete($path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new EmptyResponse(204);
|
return new EmptyResponse(204);
|
||||||
|
@@ -9,12 +9,10 @@
|
|||||||
|
|
||||||
namespace Flarum\Api\Controller;
|
namespace Flarum\Api\Controller;
|
||||||
|
|
||||||
use Flarum\Foundation\Application;
|
|
||||||
use Flarum\Settings\SettingsRepositoryInterface;
|
use Flarum\Settings\SettingsRepositoryInterface;
|
||||||
use Flarum\User\AssertPermissionTrait;
|
use Flarum\User\AssertPermissionTrait;
|
||||||
use Laminas\Diactoros\Response\EmptyResponse;
|
use Laminas\Diactoros\Response\EmptyResponse;
|
||||||
use League\Flysystem\Adapter\Local;
|
use League\Flysystem\FilesystemInterface;
|
||||||
use League\Flysystem\Filesystem;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
|
||||||
class DeleteLogoController extends AbstractDeleteController
|
class DeleteLogoController extends AbstractDeleteController
|
||||||
@@ -27,17 +25,18 @@ class DeleteLogoController extends AbstractDeleteController
|
|||||||
protected $settings;
|
protected $settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Application
|
* @var FilesystemInterface
|
||||||
*/
|
*/
|
||||||
protected $app;
|
protected $uploadDir;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param SettingsRepositoryInterface $settings
|
* @param SettingsRepositoryInterface $settings
|
||||||
|
* @param FilesystemInterface $uploadDir
|
||||||
*/
|
*/
|
||||||
public function __construct(SettingsRepositoryInterface $settings, Application $app)
|
public function __construct(SettingsRepositoryInterface $settings, FilesystemInterface $uploadDir)
|
||||||
{
|
{
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->app = $app;
|
$this->uploadDir = $uploadDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,10 +50,8 @@ class DeleteLogoController extends AbstractDeleteController
|
|||||||
|
|
||||||
$this->settings->set('logo_path', null);
|
$this->settings->set('logo_path', null);
|
||||||
|
|
||||||
$uploadDir = new Filesystem(new Local($this->app->publicPath().'/assets'));
|
if ($this->uploadDir->has($path)) {
|
||||||
|
$this->uploadDir->delete($path);
|
||||||
if ($uploadDir->has($path)) {
|
|
||||||
$uploadDir->delete($path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new EmptyResponse(204);
|
return new EmptyResponse(204);
|
||||||
|
@@ -9,15 +9,12 @@
|
|||||||
|
|
||||||
namespace Flarum\Api\Controller;
|
namespace Flarum\Api\Controller;
|
||||||
|
|
||||||
use Flarum\Foundation\Application;
|
|
||||||
use Flarum\Settings\SettingsRepositoryInterface;
|
use Flarum\Settings\SettingsRepositoryInterface;
|
||||||
use Flarum\User\AssertPermissionTrait;
|
use Flarum\User\AssertPermissionTrait;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Intervention\Image\ImageManager;
|
use Intervention\Image\ImageManager;
|
||||||
use League\Flysystem\Adapter\Local;
|
use League\Flysystem\FilesystemInterface;
|
||||||
use League\Flysystem\Filesystem;
|
|
||||||
use League\Flysystem\MountManager;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Tobscure\JsonApi\Document;
|
use Tobscure\JsonApi\Document;
|
||||||
|
|
||||||
@@ -31,17 +28,18 @@ class UploadFaviconController extends ShowForumController
|
|||||||
protected $settings;
|
protected $settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Application
|
* @var FilesystemInterface
|
||||||
*/
|
*/
|
||||||
protected $app;
|
protected $uploadDir;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param SettingsRepositoryInterface $settings
|
* @param SettingsRepositoryInterface $settings
|
||||||
|
* @param FilesystemInterface $uploadDir
|
||||||
*/
|
*/
|
||||||
public function __construct(SettingsRepositoryInterface $settings, Application $app)
|
public function __construct(SettingsRepositoryInterface $settings, FilesystemInterface $uploadDir)
|
||||||
{
|
{
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->app = $app;
|
$this->uploadDir = $uploadDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,36 +50,28 @@ class UploadFaviconController extends ShowForumController
|
|||||||
$this->assertAdmin($request->getAttribute('actor'));
|
$this->assertAdmin($request->getAttribute('actor'));
|
||||||
|
|
||||||
$file = Arr::get($request->getUploadedFiles(), 'favicon');
|
$file = Arr::get($request->getUploadedFiles(), 'favicon');
|
||||||
|
|
||||||
$tmpFile = tempnam($this->app->storagePath().'/tmp', 'favicon');
|
|
||||||
$file->moveTo($tmpFile);
|
|
||||||
|
|
||||||
$extension = pathinfo($file->getClientFilename(), PATHINFO_EXTENSION);
|
$extension = pathinfo($file->getClientFilename(), PATHINFO_EXTENSION);
|
||||||
|
|
||||||
if ($extension !== 'ico') {
|
if ($extension === 'ico') {
|
||||||
|
$image = $file->getStream();
|
||||||
|
} else {
|
||||||
$manager = new ImageManager;
|
$manager = new ImageManager;
|
||||||
|
|
||||||
$encodedImage = $manager->make($tmpFile)->resize(64, 64, function ($constraint) {
|
$image = $manager->make($file->getStream())->resize(64, 64, function ($constraint) {
|
||||||
$constraint->aspectRatio();
|
$constraint->aspectRatio();
|
||||||
$constraint->upsize();
|
$constraint->upsize();
|
||||||
})->encode('png');
|
})->encode('png');
|
||||||
file_put_contents($tmpFile, $encodedImage);
|
|
||||||
|
|
||||||
$extension = 'png';
|
$extension = 'png';
|
||||||
}
|
}
|
||||||
|
|
||||||
$mount = new MountManager([
|
if (($path = $this->settings->get('favicon_path')) && $this->uploadDir->has($path)) {
|
||||||
'source' => new Filesystem(new Local(pathinfo($tmpFile, PATHINFO_DIRNAME))),
|
$this->uploadDir->delete($path);
|
||||||
'target' => new Filesystem(new Local($this->app->publicPath().'/assets')),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (($path = $this->settings->get('favicon_path')) && $mount->has($file = "target://$path")) {
|
|
||||||
$mount->delete($file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$uploadName = 'favicon-'.Str::lower(Str::random(8)).'.'.$extension;
|
$uploadName = 'favicon-'.Str::lower(Str::random(8)).'.'.$extension;
|
||||||
|
|
||||||
$mount->move('source://'.pathinfo($tmpFile, PATHINFO_BASENAME), "target://$uploadName");
|
$this->uploadDir->write($uploadName, $image);
|
||||||
|
|
||||||
$this->settings->set('favicon_path', $uploadName);
|
$this->settings->set('favicon_path', $uploadName);
|
||||||
|
|
||||||
|
@@ -9,15 +9,12 @@
|
|||||||
|
|
||||||
namespace Flarum\Api\Controller;
|
namespace Flarum\Api\Controller;
|
||||||
|
|
||||||
use Flarum\Foundation\Application;
|
|
||||||
use Flarum\Settings\SettingsRepositoryInterface;
|
use Flarum\Settings\SettingsRepositoryInterface;
|
||||||
use Flarum\User\AssertPermissionTrait;
|
use Flarum\User\AssertPermissionTrait;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Intervention\Image\ImageManager;
|
use Intervention\Image\ImageManager;
|
||||||
use League\Flysystem\Adapter\Local;
|
use League\Flysystem\FilesystemInterface;
|
||||||
use League\Flysystem\Filesystem;
|
|
||||||
use League\Flysystem\MountManager;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Tobscure\JsonApi\Document;
|
use Tobscure\JsonApi\Document;
|
||||||
|
|
||||||
@@ -31,17 +28,18 @@ class UploadLogoController extends ShowForumController
|
|||||||
protected $settings;
|
protected $settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Application
|
* @var FilesystemInterface
|
||||||
*/
|
*/
|
||||||
protected $app;
|
protected $uploadDir;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param SettingsRepositoryInterface $settings
|
* @param SettingsRepositoryInterface $settings
|
||||||
|
* @param FilesystemInterface $uploadDir
|
||||||
*/
|
*/
|
||||||
public function __construct(SettingsRepositoryInterface $settings, Application $app)
|
public function __construct(SettingsRepositoryInterface $settings, FilesystemInterface $uploadDir)
|
||||||
{
|
{
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->app = $app;
|
$this->uploadDir = $uploadDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,28 +51,19 @@ class UploadLogoController extends ShowForumController
|
|||||||
|
|
||||||
$file = Arr::get($request->getUploadedFiles(), 'logo');
|
$file = Arr::get($request->getUploadedFiles(), 'logo');
|
||||||
|
|
||||||
$tmpFile = tempnam($this->app->storagePath().'/tmp', 'logo');
|
|
||||||
$file->moveTo($tmpFile);
|
|
||||||
|
|
||||||
$manager = new ImageManager;
|
$manager = new ImageManager;
|
||||||
|
|
||||||
$encodedImage = $manager->make($tmpFile)->heighten(60, function ($constraint) {
|
$encodedImage = $manager->make($file->getStream())->heighten(60, function ($constraint) {
|
||||||
$constraint->upsize();
|
$constraint->upsize();
|
||||||
})->encode('png');
|
})->encode('png');
|
||||||
file_put_contents($tmpFile, $encodedImage);
|
|
||||||
|
|
||||||
$mount = new MountManager([
|
if (($path = $this->settings->get('logo_path')) && $this->uploadDir->has($path)) {
|
||||||
'source' => new Filesystem(new Local(pathinfo($tmpFile, PATHINFO_DIRNAME))),
|
$this->uploadDir->delete($path);
|
||||||
'target' => new Filesystem(new Local($this->app->publicPath().'/assets')),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (($path = $this->settings->get('logo_path')) && $mount->has($file = "target://$path")) {
|
|
||||||
$mount->delete($file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$uploadName = 'logo-'.Str::lower(Str::random(8)).'.png';
|
$uploadName = 'logo-'.Str::lower(Str::random(8)).'.png';
|
||||||
|
|
||||||
$mount->move('source://'.pathinfo($tmpFile, PATHINFO_BASENAME), "target://$uploadName");
|
$this->uploadDir->write($uploadName, $encodedImage);
|
||||||
|
|
||||||
$this->settings->set('logo_path', $uploadName);
|
$this->settings->set('logo_path', $uploadName);
|
||||||
|
|
||||||
|
@@ -9,8 +9,15 @@
|
|||||||
|
|
||||||
namespace Flarum\Settings;
|
namespace Flarum\Settings;
|
||||||
|
|
||||||
|
use Flarum\Api\Controller\DeleteFaviconController;
|
||||||
|
use Flarum\Api\Controller\DeleteLogoController;
|
||||||
|
use Flarum\Api\Controller\UploadFaviconController;
|
||||||
|
use Flarum\Api\Controller\UploadLogoController;
|
||||||
use Flarum\Foundation\AbstractServiceProvider;
|
use Flarum\Foundation\AbstractServiceProvider;
|
||||||
|
use Illuminate\Contracts\Container\Container;
|
||||||
|
use Illuminate\Contracts\Filesystem\Factory;
|
||||||
use Illuminate\Database\ConnectionInterface;
|
use Illuminate\Database\ConnectionInterface;
|
||||||
|
use League\Flysystem\FilesystemInterface;
|
||||||
|
|
||||||
class SettingsServiceProvider extends AbstractServiceProvider
|
class SettingsServiceProvider extends AbstractServiceProvider
|
||||||
{
|
{
|
||||||
@@ -28,5 +35,18 @@ class SettingsServiceProvider extends AbstractServiceProvider
|
|||||||
});
|
});
|
||||||
|
|
||||||
$this->app->alias(SettingsRepositoryInterface::class, 'flarum.settings');
|
$this->app->alias(SettingsRepositoryInterface::class, 'flarum.settings');
|
||||||
|
|
||||||
|
$assets = function (Container $app) {
|
||||||
|
return $app->make(Factory::class)->disk('flarum-assets')->getDriver();
|
||||||
|
};
|
||||||
|
|
||||||
|
$this->app->when([
|
||||||
|
DeleteFaviconController::class,
|
||||||
|
DeleteLogoController::class,
|
||||||
|
UploadFaviconController::class,
|
||||||
|
UploadLogoController::class,
|
||||||
|
])
|
||||||
|
->needs(FilesystemInterface::class)
|
||||||
|
->give($assets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
namespace Flarum\User\Command;
|
namespace Flarum\User\Command;
|
||||||
|
|
||||||
use Flarum\Foundation\Application;
|
|
||||||
use Flarum\Foundation\DispatchEventsTrait;
|
use Flarum\Foundation\DispatchEventsTrait;
|
||||||
use Flarum\User\AssertPermissionTrait;
|
use Flarum\User\AssertPermissionTrait;
|
||||||
use Flarum\User\AvatarUploader;
|
use Flarum\User\AvatarUploader;
|
||||||
@@ -29,11 +28,6 @@ class UploadAvatarHandler
|
|||||||
*/
|
*/
|
||||||
protected $users;
|
protected $users;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Application
|
|
||||||
*/
|
|
||||||
protected $app;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var AvatarUploader
|
* @var AvatarUploader
|
||||||
*/
|
*/
|
||||||
@@ -47,15 +41,13 @@ class UploadAvatarHandler
|
|||||||
/**
|
/**
|
||||||
* @param Dispatcher $events
|
* @param Dispatcher $events
|
||||||
* @param UserRepository $users
|
* @param UserRepository $users
|
||||||
* @param Application $app
|
|
||||||
* @param AvatarUploader $uploader
|
* @param AvatarUploader $uploader
|
||||||
* @param AvatarValidator $validator
|
* @param AvatarValidator $validator
|
||||||
*/
|
*/
|
||||||
public function __construct(Dispatcher $events, UserRepository $users, Application $app, AvatarUploader $uploader, AvatarValidator $validator)
|
public function __construct(Dispatcher $events, UserRepository $users, AvatarUploader $uploader, AvatarValidator $validator)
|
||||||
{
|
{
|
||||||
$this->events = $events;
|
$this->events = $events;
|
||||||
$this->users = $users;
|
$this->users = $users;
|
||||||
$this->app = $app;
|
|
||||||
$this->uploader = $uploader;
|
$this->uploader = $uploader;
|
||||||
$this->validator = $validator;
|
$this->validator = $validator;
|
||||||
}
|
}
|
||||||
@@ -76,26 +68,17 @@ class UploadAvatarHandler
|
|||||||
$this->assertCan($actor, 'edit', $user);
|
$this->assertCan($actor, 'edit', $user);
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = $command->file;
|
$this->validator->assertValid(['avatar' => $command->file]);
|
||||||
|
|
||||||
$tmpFile = tempnam($this->app->storagePath().'/tmp', 'avatar');
|
$image = (new ImageManager)->make($command->file->getStream());
|
||||||
$file->moveTo($tmpFile);
|
|
||||||
|
|
||||||
try {
|
$this->events->dispatch(
|
||||||
$this->validator->assertValid(['avatar' => $file]);
|
new AvatarSaving($user, $actor, $image)
|
||||||
|
);
|
||||||
|
|
||||||
$image = (new ImageManager)->make($tmpFile);
|
$this->uploader->upload($user, $image);
|
||||||
|
|
||||||
$this->events->dispatch(
|
$user->save();
|
||||||
new AvatarSaving($user, $actor, $image)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->uploader->upload($user, $image);
|
|
||||||
|
|
||||||
$user->save();
|
|
||||||
} finally {
|
|
||||||
@unlink($tmpFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user