3 namespace BookStack\Exports\ZipExports;
5 use BookStack\Entities\Models\Book;
6 use BookStack\Entities\Models\Chapter;
7 use BookStack\Entities\Models\Entity;
8 use BookStack\Exceptions\ZipExportException;
9 use BookStack\Exceptions\ZipImportException;
10 use BookStack\Exports\Import;
11 use BookStack\Exports\ZipExports\Models\ZipExportBook;
12 use BookStack\Exports\ZipExports\Models\ZipExportChapter;
13 use BookStack\Exports\ZipExports\Models\ZipExportPage;
14 use BookStack\Uploads\FileStorage;
18 public function __construct(
19 protected FileStorage $storage,
24 * @throws ZipImportException
26 public function run(Import $import, ?Entity $parent = null): void
28 $zipPath = $this->getZipPath($import);
29 $reader = new ZipExportReader($zipPath);
31 $errors = (new ZipExportValidator($reader))->validate();
33 throw new ZipImportException(["ZIP failed to validate"]);
37 $exportModel = $reader->decodeDataToExportModel();
38 } catch (ZipExportException $e) {
39 throw new ZipImportException([$e->getMessage()]);
42 // Validate parent type
43 if ($exportModel instanceof ZipExportBook && ($parent !== null)) {
44 throw new ZipImportException(["Must not have a parent set for a Book import"]);
45 } else if ($exportModel instanceof ZipExportChapter && (!$parent instanceof Book)) {
46 throw new ZipImportException(["Parent book required for chapter import"]);
47 } else if ($exportModel instanceof ZipExportPage && !($parent instanceof Book || $parent instanceof Chapter)) {
48 throw new ZipImportException(["Parent book or chapter required for page import"]);
51 $this->ensurePermissionsPermitImport($exportModel);
57 * @throws ZipImportException
59 protected function ensurePermissionsPermitImport(ZipExportPage|ZipExportChapter|ZipExportBook $exportModel, Book|Chapter|null $parent = null): void
63 // TODO - Extract messages to language files
64 // TODO - Ensure these are shown to users on failure
71 if ($exportModel instanceof ZipExportBook) {
72 if (!userCan('book-create-all')) {
73 $errors[] = 'You are lacking the required permission to create books.';
75 array_push($pages, ...$exportModel->pages);
76 array_push($chapters, ...$exportModel->chapters);
77 } else if ($exportModel instanceof ZipExportChapter) {
78 $chapters[] = $exportModel;
79 } else if ($exportModel instanceof ZipExportPage) {
80 $pages[] = $exportModel;
83 foreach ($chapters as $chapter) {
84 array_push($pages, ...$chapter->pages);
87 if (count($chapters) > 0) {
88 $permission = 'chapter-create' . ($parent ? '' : '-all');
89 if (!userCan($permission, $parent)) {
90 $errors[] = 'You are lacking the required permission to create chapters.';
94 foreach ($pages as $page) {
95 array_push($attachments, ...$page->attachments);
96 array_push($images, ...$page->images);
99 if (count($pages) > 0) {
101 if (!userCan('page-create', $parent)) {
102 $errors[] = 'You are lacking the required permission to create pages.';
105 $hasPermission = userCan('page-create-all') || userCan('page-create-own');
106 if (!$hasPermission) {
107 $errors[] = 'You are lacking the required permission to create pages.';
112 if (count($images) > 0) {
113 if (!userCan('image-create-all')) {
114 $errors[] = 'You are lacking the required permissions to create images.';
118 if (count($attachments) > 0) {
119 if (userCan('attachment-create-all')) {
120 $errors[] = 'You are lacking the required permissions to create attachments.';
124 if (count($errors)) {
125 throw new ZipImportException($errors);
129 protected function getZipPath(Import $import): string
131 if (!$this->storage->isRemote()) {
132 return $this->storage->getSystemPath($import->path);
135 $tempFilePath = tempnam(sys_get_temp_dir(), 'bszip-import-');
136 $tempFile = fopen($tempFilePath, 'wb');
137 $stream = $this->storage->getReadStream($import->path);
138 stream_copy_to_stream($stream, $tempFile);
141 return $tempFilePath;