Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion extend.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@
use Flarum\Post\Event\Revised;
use Flarum\Settings\Event\Deserializing;
use Flarum\User\User;
use FoF\Upload\Events\File\WasSaved;
use FoF\Upload\Events\File\WillBeUploaded;
use FoF\Upload\Exceptions\ExceptionHandler;
use FoF\Upload\Exceptions\InvalidUploadException;
use FoF\Upload\Extend\SvgSanitizer;
use FoF\Upload\Extenders\LoadFilesRelationship;
use FoF\Upload\Helpers\Util;
use s9e\TextFormatter\Configurator;

return [
(new Extend\Frontend('admin'))
Expand Down Expand Up @@ -86,7 +88,8 @@
->listen(Deserializing::class, Listeners\AddAvailableOptionsInAdmin::class)
->listen(Posted::class, Listeners\LinkImageToPostOnSave::class)
->listen(Revised::class, Listeners\LinkImageToPostOnSave::class)
->listen(WillBeUploaded::class, Listeners\AddImageProcessor::class),
->listen(WillBeUploaded::class, Listeners\AddImageProcessor::class)
->listen(WasSaved::class, Listeners\AddImageMetadataProcessor::class),

(new Extend\Filesystem())
->disk('private-shared', Extenders\PrivateSharedDiskConfig::class),
Expand All @@ -108,6 +111,11 @@
->attributes(Extenders\AddUserAttributes::class),

(new Extend\Formatter())

->configure(function (Configurator $config) {
// Remove the check that prevents dynamic content in CSS
$config->templateChecker->remove('DisallowUnsafeDynamicCSS');
})
->render(Formatter\ImagePreview\FormatImagePreview::class)
->render(Formatter\TextPreview\FormatTextPreview::class),

Expand Down
40 changes: 40 additions & 0 deletions migrations/2025_08_06_000000_add_image_metadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

/*
* This file is part of fof/upload.
*
* Copyright (c) FriendsOfFlarum.
* Copyright (c) Flagrow.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Schema\Builder;

return [
'up' => function (Builder $schema) {
if ($schema->hasTable('fof_upload_image_metadata')) {
return;
}
$schema->create('fof_upload_image_metadata', function (Blueprint $table) {
$table->unsignedInteger('upload_id');
$table->uuid('file_id');
$table->unsignedInteger('image_width');
$table->unsignedInteger('image_height');

$table->primary('upload_id');

// Add foreign key constraint
$table->foreign('upload_id')
->references('id')
->on('flarum_fof_upload_files')
->onDelete('cascade');
});
},
'down' => function (Builder $schema) {
$schema->dropIfExists('fof_upload_image_metadata');
},
];

10 changes: 9 additions & 1 deletion resources/templates/image-preview.blade.php
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
<img class="FoFUpload--Upl-Image-Preview" src="{@url}" title="{@title}" alt="{@alt}" data-id="{@uuid}" loading="lazy"/>
<img
class="FoFUpload--Upl-Image-Preview"
src="{@url}"
title="{@title}"
about="{@aspectRatio}"
data-id="{@uuid}"
style="aspect-ratio: {@aspectRatio};"
loading="lazy"
/>
8 changes: 8 additions & 0 deletions src/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,12 @@ public function human_filesize(string $bytes, int $decimals = 0): string

return sprintf("%.{$decimals}f", (int) $bytes / pow(1024, $factor)).@$size[$factor];
}


public function imageMetadata(): \Illuminate\Database\Eloquent\Relations\HasOne
{
return $this->hasOne(ImageMetadata::class, 'upload_id', 'id');
}


}
8 changes: 8 additions & 0 deletions src/Formatter/ImagePreview/FormatImagePreview.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

namespace FoF\Upload\Formatter\ImagePreview;

use FoF\Upload\ImageMetadata;
use FoF\Upload\Repositories\FileRepository;
use Illuminate\Support\Arr;
use s9e\TextFormatter\Renderer;
Expand Down Expand Up @@ -57,6 +58,13 @@
$attributes['title'] = $file->base_name;
}

// Add aspect ratio if image metadata exists
$imageMetadata = ImageMetadata::byFile($file);

if ($imageMetadata && $imageMetadata->image_width && $imageMetadata->image_height) {

Check failure on line 64 in src/Formatter/ImagePreview/FormatImagePreview.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.3

Left side of && is always true.

Check failure on line 64 in src/Formatter/ImagePreview/FormatImagePreview.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.3

Access to an undefined property Illuminate\Database\Eloquent\Builder<FoF\Upload\ImageMetadata>::$image_width.

Check failure on line 64 in src/Formatter/ImagePreview/FormatImagePreview.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.3

Access to an undefined property Illuminate\Database\Eloquent\Builder<FoF\Upload\ImageMetadata>::$image_height.

Check failure on line 64 in src/Formatter/ImagePreview/FormatImagePreview.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.2

Left side of && is always true.

Check failure on line 64 in src/Formatter/ImagePreview/FormatImagePreview.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.2

Access to an undefined property Illuminate\Database\Eloquent\Builder<FoF\Upload\ImageMetadata>::$image_width.

Check failure on line 64 in src/Formatter/ImagePreview/FormatImagePreview.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.2

Access to an undefined property Illuminate\Database\Eloquent\Builder<FoF\Upload\ImageMetadata>::$image_height.

Check failure on line 64 in src/Formatter/ImagePreview/FormatImagePreview.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.1

Left side of && is always true.

Check failure on line 64 in src/Formatter/ImagePreview/FormatImagePreview.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.1

Access to an undefined property Illuminate\Database\Eloquent\Builder<FoF\Upload\ImageMetadata>::$image_width.

Check failure on line 64 in src/Formatter/ImagePreview/FormatImagePreview.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.1

Access to an undefined property Illuminate\Database\Eloquent\Builder<FoF\Upload\ImageMetadata>::$image_height.
$attributes['aspectRatio'] = $imageMetadata->image_width . "/" . $imageMetadata->image_height;
}

return $attributes;
});
}
Expand Down
60 changes: 60 additions & 0 deletions src/ImageMetadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

namespace FoF\Upload;

use Flarum\Database\AbstractModel;
use Illuminate\Database\Eloquent\Builder;

/**
* @property int $upload_id
* @property string $file_id
* @property int $image_width
* @property int $image_height
* @property File $file
*/
class ImageMetadata extends AbstractModel
{
protected $table = 'fof_upload_image_metadata';

// The primary key is 'upload_id', not 'id'
protected $primaryKey = 'upload_id';
public $incrementing = false; // because it's not auto-incrementing (as it's a foreign key)
protected $keyType = 'int';

protected $fillable = [
'file_id',
'image_width',
'image_height',
];

public static function byUuid(string $uuid): Builder
{
return static::query()
->where('uuid', $uuid);
}

public static function byFile($file): Builder|\Illuminate\Database\Eloquent\Model|null
{
if (!$file) {
return null;
}

return static::query()->where('upload_id', $file->id)->first();
}

/**
* Relation to the File model
*/
public function file(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{
return $this->belongsTo(File::class, 'upload_id', 'id');
}

/**
* Static helper to find a metadata row by upload_id
*/
public static function byUploadId(int $uploadId): \Illuminate\Database\Eloquent\Builder|null
{
return static::query()->where('upload_id', $uploadId)->first();

Check failure on line 58 in src/ImageMetadata.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.3

Method FoF\Upload\ImageMetadata::byUploadId() should return Illuminate\Database\Eloquent\Builder|null but returns FoF\Upload\ImageMetadata|null.

Check failure on line 58 in src/ImageMetadata.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.2

Method FoF\Upload\ImageMetadata::byUploadId() should return Illuminate\Database\Eloquent\Builder|null but returns FoF\Upload\ImageMetadata|null.

Check failure on line 58 in src/ImageMetadata.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.1

Method FoF\Upload\ImageMetadata::byUploadId() should return Illuminate\Database\Eloquent\Builder|null but returns FoF\Upload\ImageMetadata|null.
}
}
41 changes: 41 additions & 0 deletions src/Listeners/AddImageMetadataProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

/*
* This file is part of fof/upload.
*
* Copyright (c) FriendsOfFlarum.
* Copyright (c) Flagrow.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FoF\Upload\Listeners;

use FoF\Upload\Events\File\WasSaved;
use FoF\Upload\Processors\ImageProcessor;

class AddImageMetadataProcessor
{
public function __construct(
public ImageProcessor $processor
) {
}

public function handle(WasSaved $event): void
{
if ($this->validateMime($event->mime)) {
$this->processor->addMetadata($event->file, $event->uploadedFile, $event->mime);
}
}

protected function validateMime($mime): bool
{
return true;
if ($mime == 'image/jpeg' || $mime == 'image/png' || $mime == 'image/gif' || $mime == 'image/svg+xml') {

Check failure on line 35 in src/Listeners/AddImageMetadataProcessor.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.3

Unreachable statement - code above always terminates.

Check failure on line 35 in src/Listeners/AddImageMetadataProcessor.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.2

Unreachable statement - code above always terminates.

Check failure on line 35 in src/Listeners/AddImageMetadataProcessor.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.1

Unreachable statement - code above always terminates.
return true;
}

return false;
}
}
18 changes: 18 additions & 0 deletions src/Processors/ImageProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,22 @@ protected function watermark(Image $image)
);
}
}

public function addMetadata(File &$file, UploadedFile &$upload, string &$mime): void
{
try {
$image = (new ImageManager())->make('assets/files'.DIRECTORY_SEPARATOR.$file->path);
} catch (NotReadableException $e) {
throw new ValidationException(['upload' => 'Corrupted image']);
}

$file->imageMetadata()->create([
'upload_id' => $file->id,
'file_id' => $file->uuid ?? '',
'image_width' => $image->width(),
'image_height' => $image->height(),
]);
$file->save();

}
}
Loading