Zip Exports: Added attachment/image link resolving & JSON null handling

This commit is contained in:
Dan Brown 2024-10-21 12:13:41 +01:00
parent 7c39dd5cba
commit 06ffd8ee72
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
9 changed files with 79 additions and 10 deletions

View File

@ -5,7 +5,7 @@ namespace BookStack\Exports\ZipExportModels;
use BookStack\Exports\ZipExportFiles;
use BookStack\Uploads\Attachment;
class ZipExportAttachment implements ZipExportModel
class ZipExportAttachment extends ZipExportModel
{
public ?int $id = null;
public string $name;

View File

@ -4,7 +4,7 @@ namespace BookStack\Exports\ZipExportModels;
use BookStack\Activity\Models\Tag;
class ZipExportImage implements ZipExportModel
class ZipExportImage extends ZipExportModel
{
public string $name;
public string $file;

View File

@ -2,10 +2,19 @@
namespace BookStack\Exports\ZipExportModels;
use BookStack\App\Model;
use BookStack\Exports\ZipExportFiles;
use JsonSerializable;
interface ZipExportModel
abstract class ZipExportModel implements JsonSerializable
{
// public static function fromModel(Model $model, ZipExportFiles $files): self;
/**
* Handle the serialization to JSON.
* For these exports, we filter out optional (represented as nullable) fields
* just to clean things up and prevent confusion to avoid null states in the
* resulting export format itself.
*/
public function jsonSerialize(): array
{
$publicProps = get_object_vars(...)->__invoke($this);
return array_filter($publicProps, fn ($value) => $value !== null);
}
}

View File

@ -6,7 +6,7 @@ use BookStack\Entities\Models\Page;
use BookStack\Entities\Tools\PageContent;
use BookStack\Exports\ZipExportFiles;
class ZipExportPage implements ZipExportModel
class ZipExportPage extends ZipExportModel
{
public ?int $id = null;
public string $name;

View File

@ -4,7 +4,7 @@ namespace BookStack\Exports\ZipExportModels;
use BookStack\Activity\Models\Tag;
class ZipExportTag implements ZipExportModel
class ZipExportTag extends ZipExportModel
{
public string $name;
public ?string $value = null;

View File

@ -44,11 +44,14 @@ class ZipExportReferences
// TODO - Handle found link to $model
// - Validate we can see/access $model, or/and that it's
// part of the export in progress.
// TODO - Add images after the above to files
return '[CAT]';
});
// TODO - markdown
}
// dd('end');
// TODO - Parse chapter desc html
// TODO - Parse book desc html
}

View File

@ -4,9 +4,11 @@ namespace BookStack\Exports;
use BookStack\App\Model;
use BookStack\Entities\Queries\EntityQueries;
use BookStack\References\ModelResolvers\AttachmentModelResolver;
use BookStack\References\ModelResolvers\BookLinkModelResolver;
use BookStack\References\ModelResolvers\ChapterLinkModelResolver;
use BookStack\References\ModelResolvers\CrossLinkModelResolver;
use BookStack\References\ModelResolvers\ImageModelResolver;
use BookStack\References\ModelResolvers\PageLinkModelResolver;
use BookStack\References\ModelResolvers\PagePermalinkModelResolver;
@ -24,8 +26,8 @@ class ZipReferenceParser
new PageLinkModelResolver($queries->pages),
new ChapterLinkModelResolver($queries->chapters),
new BookLinkModelResolver($queries->books),
// TODO - Image
// TODO - Attachment
new ImageModelResolver(),
new AttachmentModelResolver(),
];
}

View File

@ -0,0 +1,22 @@
<?php
namespace BookStack\References\ModelResolvers;
use BookStack\Uploads\Attachment;
class AttachmentModelResolver implements CrossLinkModelResolver
{
public function resolve(string $link): ?Attachment
{
$pattern = '/^' . preg_quote(url('/attachments'), '/') . '\/(\d+)/';
$matches = [];
$match = preg_match($pattern, $link, $matches);
if (!$match) {
return null;
}
$id = intval($matches[1]);
return Attachment::query()->find($id);
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace BookStack\References\ModelResolvers;
use BookStack\Uploads\Image;
class ImageModelResolver implements CrossLinkModelResolver
{
public function resolve(string $link): ?Image
{
$pattern = '/^' . preg_quote(url('/uploads/images'), '/') . '\/(.+)/';
$matches = [];
$match = preg_match($pattern, $link, $matches);
if (!$match) {
return null;
}
$path = $matches[1];
// Strip thumbnail element from path if existing
$originalPathSplit = array_filter(explode('/', $path), function (string $part) {
$resizedDir = (str_starts_with($part, 'thumbs-') || str_starts_with($part, 'scaled-'));
$missingExtension = !str_contains($part, '.');
return !($resizedDir && $missingExtension);
});
// Build a database-format image path and search for the image entry
$fullPath = '/uploads/images/' . ltrim(implode('/', $originalPathSplit), '/');
return Image::query()->where('path', '=', $fullPath)->first();
}
}