mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-02-22 07:10:12 +08:00
ZIP Imports: Finished off core import logic
This commit is contained in:
parent
378f0d595f
commit
48c101aa7a
@ -7,6 +7,7 @@ class ZipImportException extends \Exception
|
||||
public function __construct(
|
||||
public array $errors
|
||||
) {
|
||||
parent::__construct();
|
||||
$message = "Import failed with errors:" . implode("\n", $this->errors);
|
||||
parent::__construct($message);
|
||||
}
|
||||
}
|
||||
|
@ -79,18 +79,21 @@ class ImportController extends Controller
|
||||
$import = $this->imports->findVisible($id);
|
||||
$parent = null;
|
||||
|
||||
if ($import->getType() === 'page' || $import->getType() === 'chapter') {
|
||||
if ($import->type === 'page' || $import->type === 'chapter') {
|
||||
$data = $this->validate($request, [
|
||||
'parent' => ['required', 'string']
|
||||
]);
|
||||
$parent = $data['parent'];
|
||||
}
|
||||
|
||||
// TODO - Run import
|
||||
// TODO - Validate again before
|
||||
// TODO - Check permissions before (create for main item, create for children, create for related items [image, attachments])
|
||||
$entity = $this->imports->runImport($import, $parent);
|
||||
if ($entity) {
|
||||
$this->logActivity(ActivityType::IMPORT_RUN, $import);
|
||||
return redirect($entity->getUrl());
|
||||
}
|
||||
// TODO - Redirect to result
|
||||
// TODO - Or redirect back with errors
|
||||
return 'failed';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,9 +2,11 @@
|
||||
|
||||
namespace BookStack\Exports;
|
||||
|
||||
use BookStack\Entities\Models\Entity;
|
||||
use BookStack\Entities\Queries\EntityQueries;
|
||||
use BookStack\Exceptions\FileUploadException;
|
||||
use BookStack\Exceptions\ZipExportException;
|
||||
use BookStack\Exceptions\ZipImportException;
|
||||
use BookStack\Exceptions\ZipValidationException;
|
||||
use BookStack\Exports\ZipExports\Models\ZipExportBook;
|
||||
use BookStack\Exports\ZipExports\Models\ZipExportChapter;
|
||||
@ -95,9 +97,9 @@ class ImportRepo
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ZipValidationException
|
||||
* @throws ZipValidationException|ZipImportException
|
||||
*/
|
||||
public function runImport(Import $import, ?string $parent = null)
|
||||
public function runImport(Import $import, ?string $parent = null): ?Entity
|
||||
{
|
||||
$parentModel = null;
|
||||
if ($import->type === 'page' || $import->type === 'chapter') {
|
||||
|
@ -110,7 +110,7 @@ class ZipImportReferences
|
||||
{
|
||||
foreach ($this->books as $book) {
|
||||
$exportBook = $this->zipExportBookMap[$book->id];
|
||||
$content = $exportBook->description_html || '';
|
||||
$content = $exportBook->description_html ?? '';
|
||||
$parsed = $this->parser->parseReferences($content, $this->handleReference(...));
|
||||
|
||||
$this->baseRepo->update($book, [
|
||||
@ -120,7 +120,7 @@ class ZipImportReferences
|
||||
|
||||
foreach ($this->chapters as $chapter) {
|
||||
$exportChapter = $this->zipExportChapterMap[$chapter->id];
|
||||
$content = $exportChapter->description_html || '';
|
||||
$content = $exportChapter->description_html ?? '';
|
||||
$parsed = $this->parser->parseReferences($content, $this->handleReference(...));
|
||||
|
||||
$this->baseRepo->update($chapter, [
|
||||
|
@ -12,17 +12,22 @@ use BookStack\Entities\Repos\PageRepo;
|
||||
use BookStack\Exceptions\ZipExportException;
|
||||
use BookStack\Exceptions\ZipImportException;
|
||||
use BookStack\Exports\Import;
|
||||
use BookStack\Exports\ZipExports\Models\ZipExportAttachment;
|
||||
use BookStack\Exports\ZipExports\Models\ZipExportBook;
|
||||
use BookStack\Exports\ZipExports\Models\ZipExportChapter;
|
||||
use BookStack\Exports\ZipExports\Models\ZipExportImage;
|
||||
use BookStack\Exports\ZipExports\Models\ZipExportPage;
|
||||
use BookStack\Exports\ZipExports\Models\ZipExportTag;
|
||||
use BookStack\Uploads\Attachment;
|
||||
use BookStack\Uploads\AttachmentService;
|
||||
use BookStack\Uploads\FileStorage;
|
||||
use BookStack\Uploads\Image;
|
||||
use BookStack\Uploads\ImageService;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
|
||||
class ZipImportRunner
|
||||
{
|
||||
protected array $tempFilesToCleanup = []; // TODO
|
||||
protected array $tempFilesToCleanup = [];
|
||||
|
||||
public function __construct(
|
||||
protected FileStorage $storage,
|
||||
@ -30,14 +35,19 @@ class ZipImportRunner
|
||||
protected ChapterRepo $chapterRepo,
|
||||
protected BookRepo $bookRepo,
|
||||
protected ImageService $imageService,
|
||||
protected AttachmentService $attachmentService,
|
||||
protected ZipImportReferences $references,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the import.
|
||||
* Performs re-validation on zip, validation on parent provided, and permissions for importing
|
||||
* the planned content, before running the import process.
|
||||
* Returns the top-level entity item which was imported.
|
||||
* @throws ZipImportException
|
||||
*/
|
||||
public function run(Import $import, ?Entity $parent = null): void
|
||||
public function run(Import $import, ?Entity $parent = null): ?Entity
|
||||
{
|
||||
$zipPath = $this->getZipPath($import);
|
||||
$reader = new ZipExportReader($zipPath);
|
||||
@ -63,8 +73,16 @@ class ZipImportRunner
|
||||
}
|
||||
|
||||
$this->ensurePermissionsPermitImport($exportModel);
|
||||
$entity = null;
|
||||
|
||||
if ($exportModel instanceof ZipExportBook) {
|
||||
$entity = $this->importBook($exportModel, $reader);
|
||||
} else if ($exportModel instanceof ZipExportChapter) {
|
||||
$entity = $this->importChapter($exportModel, $parent, $reader);
|
||||
} else if ($exportModel instanceof ZipExportPage) {
|
||||
$entity = $this->importPage($exportModel, $parent, $reader);
|
||||
}
|
||||
|
||||
// TODO - Run import
|
||||
// TODO - In transaction?
|
||||
// TODO - Revert uploaded files if goes wrong
|
||||
// TODO - Attachments
|
||||
@ -72,6 +90,23 @@ class ZipImportRunner
|
||||
// (Both listed/stored in references)
|
||||
|
||||
$this->references->replaceReferences();
|
||||
|
||||
$reader->close();
|
||||
$this->cleanup();
|
||||
|
||||
dd('stop');
|
||||
|
||||
// TODO - Delete import/zip after import?
|
||||
// Do this in parent repo?
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
protected function cleanup()
|
||||
{
|
||||
foreach ($this->tempFilesToCleanup as $file) {
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
protected function importBook(ZipExportBook $exportBook, ZipExportReader $reader): Book
|
||||
@ -83,17 +118,26 @@ class ZipImportRunner
|
||||
'tags' => $this->exportTagsToInputArray($exportBook->tags ?? []),
|
||||
]);
|
||||
|
||||
// TODO - Parse/format description_html references
|
||||
|
||||
if ($book->cover) {
|
||||
$this->references->addImage($book->cover, null);
|
||||
}
|
||||
|
||||
// TODO - Pages
|
||||
foreach ($exportBook->chapters as $exportChapter) {
|
||||
$this->importChapter($exportChapter, $book, $reader);
|
||||
$children = [
|
||||
...$exportBook->chapters,
|
||||
...$exportBook->pages,
|
||||
];
|
||||
|
||||
usort($children, function (ZipExportPage|ZipExportChapter $a, ZipExportPage|ZipExportChapter $b) {
|
||||
return ($a->priority ?? 0) - ($b->priority ?? 0);
|
||||
});
|
||||
|
||||
foreach ($children as $child) {
|
||||
if ($child instanceof ZipExportChapter) {
|
||||
$this->importChapter($child, $book, $reader);
|
||||
} else if ($child instanceof ZipExportPage) {
|
||||
$this->importPage($child, $book, $reader);
|
||||
}
|
||||
}
|
||||
// TODO - Sort chapters/pages by order
|
||||
|
||||
$this->references->addBook($book, $exportBook);
|
||||
|
||||
@ -108,17 +152,14 @@ class ZipImportRunner
|
||||
'tags' => $this->exportTagsToInputArray($exportChapter->tags ?? []),
|
||||
], $parent);
|
||||
|
||||
// TODO - Parse/format description_html references
|
||||
|
||||
$exportPages = $exportChapter->pages;
|
||||
usort($exportPages, function (ZipExportPage $a, ZipExportPage $b) {
|
||||
return ($a->priority ?? 0) - ($b->priority ?? 0);
|
||||
});
|
||||
|
||||
foreach ($exportPages as $exportPage) {
|
||||
//
|
||||
$this->importPage($exportPage, $chapter, $reader);
|
||||
}
|
||||
// TODO - Pages
|
||||
|
||||
$this->references->addChapter($chapter, $exportChapter);
|
||||
|
||||
@ -129,11 +170,13 @@ class ZipImportRunner
|
||||
{
|
||||
$page = $this->pageRepo->getNewDraftPage($parent);
|
||||
|
||||
// TODO - Import attachments
|
||||
// TODO - Add attachment references
|
||||
// TODO - Import images
|
||||
// TODO - Add image references
|
||||
// TODO - Parse/format HTML
|
||||
foreach ($exportPage->attachments as $exportAttachment) {
|
||||
$this->importAttachment($exportAttachment, $page, $reader);
|
||||
}
|
||||
|
||||
foreach ($exportPage->images as $exportImage) {
|
||||
$this->importImage($exportImage, $page, $reader);
|
||||
}
|
||||
|
||||
$this->pageRepo->publishDraft($page, [
|
||||
'name' => $exportPage->name,
|
||||
@ -147,6 +190,40 @@ class ZipImportRunner
|
||||
return $page;
|
||||
}
|
||||
|
||||
protected function importAttachment(ZipExportAttachment $exportAttachment, Page $page, ZipExportReader $reader): Attachment
|
||||
{
|
||||
if ($exportAttachment->file) {
|
||||
$file = $this->zipFileToUploadedFile($exportAttachment->file, $reader);
|
||||
$attachment = $this->attachmentService->saveNewUpload($file, $page->id);
|
||||
$attachment->name = $exportAttachment->name;
|
||||
$attachment->save();
|
||||
} else {
|
||||
$attachment = $this->attachmentService->saveNewFromLink(
|
||||
$exportAttachment->name,
|
||||
$exportAttachment->link ?? '',
|
||||
$page->id,
|
||||
);
|
||||
}
|
||||
|
||||
$this->references->addAttachment($attachment, $exportAttachment->id);
|
||||
|
||||
return $attachment;
|
||||
}
|
||||
|
||||
protected function importImage(ZipExportImage $exportImage, Page $page, ZipExportReader $reader): Image
|
||||
{
|
||||
$file = $this->zipFileToUploadedFile($exportImage->file, $reader);
|
||||
$image = $this->imageService->saveNewFromUpload(
|
||||
$file,
|
||||
$exportImage->type,
|
||||
$page->id,
|
||||
);
|
||||
|
||||
$this->references->addImage($image, $exportImage->id);
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
protected function exportTagsToInputArray(array $exportTags): array
|
||||
{
|
||||
$tags = [];
|
||||
@ -235,7 +312,7 @@ class ZipImportRunner
|
||||
}
|
||||
|
||||
if (count($attachments) > 0) {
|
||||
if (userCan('attachment-create-all')) {
|
||||
if (!userCan('attachment-create-all')) {
|
||||
$errors[] = 'You are lacking the required permissions to create attachments.';
|
||||
}
|
||||
}
|
||||
@ -257,6 +334,8 @@ class ZipImportRunner
|
||||
stream_copy_to_stream($stream, $tempFile);
|
||||
fclose($tempFile);
|
||||
|
||||
$this->tempFilesToCleanup[] = $tempFilePath;
|
||||
|
||||
return $tempFilePath;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user