feat: upgrade intervention/image to 3.2 (#3947)

* chore: create standalone imageprovider

* chore: upgrade intervention to v3

* Apply fixes from StyleCI

* use new static instatiation

* Revert "Apply fixes from StyleCI"

This reverts commit 096b4d9a79fa41c948a7572cf65316ebc6b07d36.

* get avatar from remote

* Apply fixes from StyleCI

* fix: incorrect gid exception namespace

* fix test

* remove debug code

---------

Co-authored-by: StyleCI Bot <bot@styleci.io>
This commit is contained in:
IanM 2024-01-19 10:49:00 +00:00 committed by GitHub
parent d400dcbc2f
commit e3350543af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 113 additions and 60 deletions

View File

@ -130,7 +130,7 @@
"illuminate/support": "^10.0",
"illuminate/validation": "^10.0",
"illuminate/view": "^10.0",
"intervention/image": "^2.7.2",
"intervention/image": "^3.2",
"jenssegers/agent": "^2.6",
"laminas/laminas-diactoros": "^3.0",
"laminas/laminas-httphandlerrunner": "^2.6",

View File

@ -59,7 +59,7 @@
"illuminate/support": "^10.0",
"illuminate/validation": "^10.0",
"illuminate/view": "^10.0",
"intervention/image": "^2.7.2",
"intervention/image": "^3.2",
"jenssegers/agent": "^2.6.4",
"laminas/laminas-diactoros": "^3.0",
"laminas/laminas-httphandlerrunner": "^2.6.1",

View File

@ -13,8 +13,8 @@ use Flarum\Foundation\ValidationException;
use Flarum\Locale\TranslatorInterface;
use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\Filesystem\Factory;
use Intervention\Image\Image;
use Intervention\Image\ImageManager;
use Intervention\Image\Interfaces\EncodedImageInterface;
use Psr\Http\Message\UploadedFileInterface;
class UploadFaviconController extends UploadImageController
@ -31,7 +31,7 @@ class UploadFaviconController extends UploadImageController
parent::__construct($settings, $filesystemFactory);
}
protected function makeImage(UploadedFileInterface $file): Image
protected function makeImage(UploadedFileInterface $file): EncodedImageInterface
{
$this->fileExtension = pathinfo($file->getClientFilename(), PATHINFO_EXTENSION);
@ -45,10 +45,9 @@ class UploadFaviconController extends UploadImageController
]);
}
$encodedImage = $this->imageManager->make($file->getStream()->getMetadata('uri'))->resize(64, 64, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->encode('png');
$encodedImage = $this->imageManager->read($file->getStream()->getMetadata('uri'))
->scale(64, 64)
->toPng();
$this->fileExtension = 'png';

View File

@ -15,7 +15,7 @@ use Illuminate\Contracts\Filesystem\Factory;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\EncodedImageInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UploadedFileInterface;
use Tobscure\JsonApi\Document;
@ -55,5 +55,5 @@ abstract class UploadImageController extends ShowForumController
return parent::data($request, $document);
}
abstract protected function makeImage(UploadedFileInterface $file): Image;
abstract protected function makeImage(UploadedFileInterface $file): EncodedImageInterface;
}

View File

@ -11,8 +11,8 @@ namespace Flarum\Api\Controller;
use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\Filesystem\Factory;
use Intervention\Image\Image;
use Intervention\Image\ImageManager;
use Intervention\Image\Interfaces\EncodedImageInterface;
use Psr\Http\Message\UploadedFileInterface;
class UploadLogoController extends UploadImageController
@ -28,11 +28,11 @@ class UploadLogoController extends UploadImageController
parent::__construct($settings, $filesystemFactory);
}
protected function makeImage(UploadedFileInterface $file): Image
protected function makeImage(UploadedFileInterface $file): EncodedImageInterface
{
$encodedImage = $this->imageManager->make($file->getStream()->getMetadata('uri'))->heighten(60, function ($constraint) {
$constraint->upsize();
})->encode('png');
$encodedImage = $this->imageManager->read($file->getStream()->getMetadata('uri'))
->scale(height: 60)
->toPng();
return $encodedImage;
}

View File

@ -10,20 +10,14 @@
namespace Flarum\Filesystem;
use Flarum\Foundation\AbstractServiceProvider;
use Flarum\Foundation\Config;
use Flarum\Foundation\Paths;
use Flarum\Http\UrlGenerator;
use Illuminate\Contracts\Container\Container;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Arr;
use Intervention\Image\ImageManager;
use League\Flysystem\Visibility;
use RuntimeException;
class FilesystemServiceProvider extends AbstractServiceProvider
{
protected const INTERVENTION_DRIVERS = ['gd' => 'gd', 'imagick' => 'imagick'];
public function register(): void
{
$this->container->singleton('files', function () {
@ -65,26 +59,5 @@ class FilesystemServiceProvider extends AbstractServiceProvider
$container->make('flarum.filesystem.resolved_drivers')
);
});
$this->container->singleton(ImageManager::class, function (Container $container) {
/** @var Config $config */
$config = $this->container->make(Config::class);
$intervention = $config->offsetGet('intervention');
$driver = Arr::get($intervention, 'driver', self::INTERVENTION_DRIVERS['gd']);
// Check that the imagick library is actually available, else default back to gd.
if ($driver === self::INTERVENTION_DRIVERS['imagick'] && ! extension_loaded(self::INTERVENTION_DRIVERS['imagick'])) {
$driver = self::INTERVENTION_DRIVERS['gd'];
}
if (! Arr::has(self::INTERVENTION_DRIVERS, $driver)) {
throw new RuntimeException("intervention/image: $driver is not valid");
}
return new ImageManager([
'driver' => $driver
]);
});
}
}

View File

@ -23,6 +23,7 @@ use Flarum\Forum\ForumServiceProvider;
use Flarum\Frontend\FrontendServiceProvider;
use Flarum\Group\GroupServiceProvider;
use Flarum\Http\HttpServiceProvider;
use Flarum\Image\ImageServiceProvider;
use Flarum\Locale\LocaleServiceProvider;
use Flarum\Mail\MailServiceProvider;
use Flarum\Notification\NotificationServiceProvider;
@ -115,6 +116,7 @@ class InstalledSite implements SiteInterface
$app->register(GroupServiceProvider::class);
$app->register(HashServiceProvider::class);
$app->register(HttpServiceProvider::class);
$app->register(ImageServiceProvider::class);
$app->register(LocaleServiceProvider::class);
$app->register(MailServiceProvider::class);
$app->register(NotificationServiceProvider::class);

View File

@ -0,0 +1,53 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Image;
use Flarum\Foundation\AbstractServiceProvider;
use Flarum\Foundation\Config;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Arr;
use Intervention\Image\Drivers;
use Intervention\Image\ImageManager;
use RuntimeException;
class ImageServiceProvider extends AbstractServiceProvider
{
public function register(): void
{
$this->container->bind('image.drivers', function (): array {
return [
'gd' => Drivers\Gd\Driver::class,
'imagick' => Drivers\Imagick\Driver::class
];
});
$this->container->singleton('image', function (Container $container): ImageManager {
$interventionDrivers = $container->make('image.drivers');
$configDriver = $container->make(Config::class)->offsetGet('intervention.driver');
// Default to 'gd' if not present in the config
$driver = $configDriver ?? 'gd';
// Check that the imagick library is actually available, else default back to gd.
if ($driver === 'imagick' && ! extension_loaded('imagick')) {
$driver = 'gd';
}
if (! Arr::has($interventionDrivers, $driver)) {
throw new RuntimeException("intervention/image: $driver is not valid");
}
return new ImageManager($interventionDrivers[$driver]);
});
$this->container->alias('image', ImageManager::class);
}
}

View File

@ -12,7 +12,7 @@ namespace Flarum\User;
use Illuminate\Contracts\Filesystem\Factory;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Str;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\ImageInterface;
class AvatarUploader
{
@ -23,16 +23,19 @@ class AvatarUploader
$this->uploadDir = $filesystemFactory->disk('flarum-avatars');
}
public function upload(User $user, Image $image): void
public function upload(User $user, ImageInterface $image): void
{
if (extension_loaded('exif')) {
$image->orientate();
$image = $image->cover(100, 100);
$avatarPath = Str::random();
if ($image->isAnimated()) {
$encodedImage = $image->toGif();
$avatarPath .= '.gif';
} else {
$encodedImage = $image->toPng();
$avatarPath .= '.png';
}
$encodedImage = $image->fit(100, 100)->encode('png');
$avatarPath = Str::random().'.png';
$this->removeFileAfterSave($user);
$user->changeAvatarPath($avatarPath);

View File

@ -14,7 +14,8 @@ use Flarum\Foundation\ValidationException;
use Flarum\Locale\TranslatorInterface;
use Illuminate\Validation\Factory;
use Illuminate\Validation\Validator;
use Intervention\Image\Exception\NotReadableException;
use Intervention\Gif\Exceptions\DecoderException as GifDecoderException;
use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\ImageManager;
use Psr\Http\Message\UploadedFileInterface;
use Symfony\Component\Mime\MimeTypes;
@ -76,8 +77,8 @@ class AvatarValidator extends AbstractValidator
}
try {
$this->imageManager->make($file->getStream()->getMetadata('uri'));
} catch (NotReadableException) {
$this->imageManager->read($file->getStream()->getMetadata('uri'));
} catch (DecoderException|GifDecoderException) {
$this->raise('image');
}
}

View File

@ -18,6 +18,7 @@ use Flarum\User\Exception\PermissionDeniedException;
use Flarum\User\RegistrationToken;
use Flarum\User\User;
use Flarum\User\UserValidator;
use GuzzleHttp\Client;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
@ -135,9 +136,30 @@ class RegisterUserHandler
throw new InvalidArgumentException("Provided avatar URL must have scheme http or https. Scheme provided was $scheme.", 503);
}
$image = $this->imageManager->make($url);
$urlContents = $this->retrieveAvatarFromUrl($url);
$this->avatarUploader->upload($user, $image);
if ($urlContents !== null) {
$image = $this->imageManager->read($urlContents);
$this->avatarUploader->upload($user, $image);
}
}
private function retrieveAvatarFromUrl(string $url): ?string
{
$client = new Client();
try {
$response = $client->get($url);
} catch (\Exception $e) {
return null;
}
if ($response->getStatusCode() !== 200) {
return null;
}
return $response->getBody()->getContents();
}
private function fulfillToken(User $user, RegistrationToken $token): void

View File

@ -43,7 +43,7 @@ class UploadAvatarHandler
$this->validator->assertValid(['avatar' => $command->file]);
$image = $this->imageManager->make($command->file->getStream()->getMetadata('uri'));
$image = $this->imageManager->read($command->file->getStream()->getMetadata('uri'));
$this->events->dispatch(
new AvatarSaving($user, $actor, $image)

View File

@ -10,14 +10,14 @@
namespace Flarum\User\Event;
use Flarum\User\User;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\ImageInterface;
class AvatarSaving
{
public function __construct(
public User $user,
public User $actor,
public Image $image
public ImageInterface $image
) {
}
}

View File

@ -16,7 +16,7 @@ use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Contracts\Filesystem\Factory;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Database\Eloquent\Model;
use Intervention\Image\ImageManagerStatic;
use Intervention\Image\ImageManager;
use Mockery as m;
class AvatarUploaderTest extends TestCase
@ -93,7 +93,7 @@ class AvatarUploaderTest extends TestCase
$user->changeAvatarPath('ABCDEFGHabcdefgh.png');
$user->syncOriginal();
$this->uploader->upload($user, ImageManagerStatic::canvas(50, 50));
$this->uploader->upload($user, ImageManager::gd()->create(50, 50));
// Simulate saving
foreach ($user->releaseAfterSaveCallbacks() as $callback) {