Skip to content

Commit

Permalink
feat: upgrade intervention/image to 3.2 (#3947)
Browse files Browse the repository at this point in the history
* 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 096b4d9.

* 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>
  • Loading branch information
imorland and StyleCIBot authored Jan 19, 2024
1 parent d400dcb commit e335054
Show file tree
Hide file tree
Showing 14 changed files with 113 additions and 60 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion framework/core/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
11 changes: 5 additions & 6 deletions framework/core/src/Api/Controller/UploadFaviconController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
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
Expand All @@ -31,7 +31,7 @@ public function __construct(
parent::__construct($settings, $filesystemFactory);
}

protected function makeImage(UploadedFileInterface $file): Image
protected function makeImage(UploadedFileInterface $file): EncodedImageInterface
{
$this->fileExtension = pathinfo($file->getClientFilename(), PATHINFO_EXTENSION);

Expand All @@ -45,10 +45,9 @@ protected function makeImage(UploadedFileInterface $file): Image
]);
}

$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';

Expand Down
4 changes: 2 additions & 2 deletions framework/core/src/Api/Controller/UploadImageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
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;
Expand Down Expand Up @@ -55,5 +55,5 @@ public function data(ServerRequestInterface $request, Document $document): array
return parent::data($request, $document);
}

abstract protected function makeImage(UploadedFileInterface $file): Image;
abstract protected function makeImage(UploadedFileInterface $file): EncodedImageInterface;
}
10 changes: 5 additions & 5 deletions framework/core/src/Api/Controller/UploadLogoController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

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
Expand All @@ -28,11 +28,11 @@ public function __construct(
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;
}
Expand Down
27 changes: 0 additions & 27 deletions framework/core/src/Filesystem/FilesystemServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down Expand Up @@ -65,26 +59,5 @@ public function register(): void
$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
]);
});
}
}
2 changes: 2 additions & 0 deletions framework/core/src/Foundation/InstalledSite.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
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;
Expand Down Expand Up @@ -115,6 +116,7 @@ protected function bootLaravel(): Container
$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);
Expand Down
53 changes: 53 additions & 0 deletions framework/core/src/Image/ImageServiceProvider.php
Original file line number Diff line number Diff line change
@@ -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);
}
}
19 changes: 11 additions & 8 deletions framework/core/src/User/AvatarUploader.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
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
{
Expand All @@ -23,15 +23,18 @@ public function __construct(Factory $filesystemFactory)
$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();
}

$encodedImage = $image->fit(100, 100)->encode('png');
$image = $image->cover(100, 100);
$avatarPath = Str::random();

$avatarPath = Str::random().'.png';
if ($image->isAnimated()) {
$encodedImage = $image->toGif();
$avatarPath .= '.gif';
} else {
$encodedImage = $image->toPng();
$avatarPath .= '.png';
}

$this->removeFileAfterSave($user);
$user->changeAvatarPath($avatarPath);
Expand Down
7 changes: 4 additions & 3 deletions framework/core/src/User/AvatarValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
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;
Expand Down Expand Up @@ -76,8 +77,8 @@ protected function assertFileMimes(UploadedFileInterface $file): void
}

try {
$this->imageManager->make($file->getStream()->getMetadata('uri'));
} catch (NotReadableException) {
$this->imageManager->read($file->getStream()->getMetadata('uri'));
} catch (DecoderException|GifDecoderException) {
$this->raise('image');
}
}
Expand Down
26 changes: 24 additions & 2 deletions framework/core/src/User/Command/RegisterUserHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
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;
Expand Down Expand Up @@ -135,9 +136,30 @@ private function uploadAvatarFromUrl(User $user, string $url): void
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
Expand Down
2 changes: 1 addition & 1 deletion framework/core/src/User/Command/UploadAvatarHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public function handle(UploadAvatar $command): User

$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)
Expand Down
4 changes: 2 additions & 2 deletions framework/core/src/User/Event/AvatarSaving.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
) {
}
}
4 changes: 2 additions & 2 deletions framework/core/tests/unit/User/AvatarUploaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
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
Expand Down Expand Up @@ -93,7 +93,7 @@ public function test_changing_avatar_removes_file()
$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) {
Expand Down

0 comments on commit e335054

Please sign in to comment.