]> BookStack Code Mirror - bookstack/blob - tests/Exports/ZipImportRunnerTest.php
ZIP Imports: Covered import runner with further testing
[bookstack] / tests / Exports / ZipImportRunnerTest.php
1 <?php
2
3 namespace Tests\Exports;
4
5 use BookStack\Entities\Models\Book;
6 use BookStack\Entities\Models\Chapter;
7 use BookStack\Entities\Models\Page;
8 use BookStack\Exports\ZipExports\ZipImportRunner;
9 use BookStack\Uploads\Image;
10 use Tests\TestCase;
11
12 class ZipImportRunnerTest extends TestCase
13 {
14     protected ZipImportRunner $runner;
15
16     protected function setUp(): void
17     {
18         parent::setUp();
19         $this->runner = app()->make(ZipImportRunner::class);
20     }
21
22     public function test_book_import()
23     {
24         $testImagePath = $this->files->testFilePath('test-image.png');
25         $testFilePath = $this->files->testFilePath('test-file.txt');
26         $import = ZipTestHelper::importFromData([], [
27             'book' => [
28                 'id' => 5,
29                 'name' => 'Import test',
30                 'cover' => 'book_cover_image',
31                 'description_html' => '<p><a href="[[bsexport:page:3]]">Link to chapter page</a></p>',
32                 'tags' => [
33                     ['name' => 'Animal', 'value' => 'Cat'],
34                     ['name' => 'Category', 'value' => 'Test'],
35                 ],
36                 'chapters' => [
37                     [
38                         'id' => 6,
39                         'name' => 'Chapter A',
40                         'description_html' => '<p><a href="[[bsexport:book:5]]">Link to book</a></p>',
41                         'priority' => 1,
42                         'tags' => [
43                             ['name' => 'Reviewed'],
44                             ['name' => 'Category', 'value' => 'Test Chapter'],
45                         ],
46                         'pages' => [
47                             [
48                                 'id' => 3,
49                                 'name' => 'Page A',
50                                 'priority' => 6,
51                                 'html' => '
52 <p><a href="[[bsexport:page:3]]">Link to self</a></p>
53 <p><a href="[[bsexport:image:1]]">Link to cat image</a></p>
54 <p><a href="[[bsexport:attachment:4]]">Link to text attachment</a></p>',
55                                 'tags' => [
56                                     ['name' => 'Unreviewed'],
57                                 ],
58                                 'attachments' => [
59                                     [
60                                         'id' => 4,
61                                         'name' => 'Text attachment',
62                                         'file' => 'file_attachment'
63                                     ],
64                                     [
65                                         'name' => 'Cats',
66                                         'link' => 'https://example.com/cats',
67                                     ]
68                                 ],
69                                 'images' => [
70                                     [
71                                         'id' => 1,
72                                         'name' => 'Cat',
73                                         'type' => 'gallery',
74                                         'file' => 'cat_image'
75                                     ],
76                                     [
77                                         'id' => 2,
78                                         'name' => 'Dog Drawing',
79                                         'type' => 'drawio',
80                                         'file' => 'dog_image'
81                                     ]
82                                 ],
83                             ],
84                         ],
85                     ],
86                     [
87                         'name' => 'Chapter child B',
88                         'priority' => 5,
89                     ]
90                 ],
91                 'pages' => [
92                     [
93                         'name' => 'Page C',
94                         'markdown' => '[Link to text]([[bsexport:attachment:4]]?scale=big)',
95                         'priority' => 3,
96                     ]
97                 ],
98             ],
99         ], [
100             'book_cover_image' => $testImagePath,
101             'file_attachment'  => $testFilePath,
102             'cat_image' => $testImagePath,
103             'dog_image' => $testImagePath,
104         ]);
105
106         $this->asAdmin();
107         /** @var Book $book */
108         $book = $this->runner->run($import);
109
110         // Book checks
111         $this->assertEquals('Import test', $book->name);
112         $this->assertFileExists(public_path($book->cover->path));
113         $this->assertCount(2, $book->tags);
114         $this->assertEquals('Cat', $book->tags()->first()->value);
115         $this->assertCount(2, $book->chapters);
116         $this->assertEquals(1, $book->directPages()->count());
117
118         // Chapter checks
119         $chapterA = $book->chapters()->where('name', 'Chapter A')->first();
120         $this->assertCount(2, $chapterA->tags);
121         $firstChapterTag = $chapterA->tags()->first();
122         $this->assertEquals('Reviewed', $firstChapterTag->name);
123         $this->assertEquals('', $firstChapterTag->value);
124         $this->assertCount(1, $chapterA->pages);
125
126         // Page checks
127         /** @var Page $pageA */
128         $pageA = $chapterA->pages->first();
129         $this->assertEquals('Page A', $pageA->name);
130         $this->assertCount(1, $pageA->tags);
131         $firstPageTag = $pageA->tags()->first();
132         $this->assertEquals('Unreviewed', $firstPageTag->name);
133         $this->assertCount(2, $pageA->attachments);
134         $firstAttachment = $pageA->attachments->first();
135         $this->assertEquals('Text attachment', $firstAttachment->name);
136         $this->assertFileEquals($testFilePath, storage_path($firstAttachment->path));
137         $this->assertFalse($firstAttachment->external);
138         $secondAttachment = $pageA->attachments->last();
139         $this->assertEquals('Cats', $secondAttachment->name);
140         $this->assertEquals('https://example.com/cats', $secondAttachment->path);
141         $this->assertTrue($secondAttachment->external);
142         $pageAImages = Image::where('uploaded_to', '=', $pageA->id)->whereIn('type', ['gallery', 'drawio'])->get();
143         $this->assertCount(2, $pageAImages);
144         $this->assertEquals('Cat', $pageAImages[0]->name);
145         $this->assertEquals('gallery', $pageAImages[0]->type);
146         $this->assertFileEquals($testImagePath, public_path($pageAImages[0]->path));
147         $this->assertEquals('Dog Drawing', $pageAImages[1]->name);
148         $this->assertEquals('drawio', $pageAImages[1]->type);
149
150         // Book order check
151         $children = $book->getDirectVisibleChildren()->values()->all();
152         $this->assertEquals($children[0]->name, 'Chapter A');
153         $this->assertEquals($children[1]->name, 'Page C');
154         $this->assertEquals($children[2]->name, 'Chapter child B');
155
156         // Reference checks
157         $textAttachmentUrl = $firstAttachment->getUrl();
158         $this->assertStringContainsString($pageA->getUrl(), $book->description_html);
159         $this->assertStringContainsString($book->getUrl(), $chapterA->description_html);
160         $this->assertStringContainsString($pageA->getUrl(), $pageA->html);
161         $this->assertStringContainsString($pageAImages[0]->getThumb(1680, null, true), $pageA->html);
162         $this->assertStringContainsString($firstAttachment->getUrl(), $pageA->html);
163
164         // Reference in converted markdown
165         $pageC = $children[1];
166         $this->assertStringContainsString("href=\"{$textAttachmentUrl}?scale=big\"", $pageC->html);
167
168         ZipTestHelper::deleteZipForImport($import);
169     }
170
171     public function test_chapter_import()
172     {
173         $testImagePath = $this->files->testFilePath('test-image.png');
174         $testFilePath = $this->files->testFilePath('test-file.txt');
175         $parent = $this->entities->book();
176
177         $import = ZipTestHelper::importFromData([], [
178             'chapter' => [
179                 'id' => 6,
180                 'name' => 'Chapter A',
181                 'description_html' => '<p><a href="[[bsexport:page:3]]">Link to page</a></p>',
182                 'priority' => 1,
183                 'tags' => [
184                     ['name' => 'Reviewed', 'value' => '2024'],
185                 ],
186                 'pages' => [
187                     [
188                         'id' => 3,
189                         'name' => 'Page A',
190                         'priority' => 6,
191                         'html' => '<p><a href="[[bsexport:chapter:6]]">Link to chapter</a></p>
192 <p><a href="[[bsexport:image:2]]">Link to dog drawing</a></p>
193 <p><a href="[[bsexport:attachment:4]]">Link to text attachment</a></p>',
194                         'tags' => [
195                             ['name' => 'Unreviewed'],
196                         ],
197                         'attachments' => [
198                             [
199                                 'id' => 4,
200                                 'name' => 'Text attachment',
201                                 'file' => 'file_attachment'
202                             ]
203                         ],
204                         'images' => [
205                             [
206                                 'id' => 2,
207                                 'name' => 'Dog Drawing',
208                                 'type' => 'drawio',
209                                 'file' => 'dog_image'
210                             ]
211                         ],
212                     ],
213                     [
214                         'name' => 'Page B',
215                         'markdown' => '[Link to page A]([[bsexport:page:3]])',
216                         'priority' => 9,
217                     ],
218                 ],
219             ],
220         ], [
221             'file_attachment'  => $testFilePath,
222             'dog_image' => $testImagePath,
223         ]);
224
225         $this->asAdmin();
226         /** @var Chapter $chapter */
227         $chapter = $this->runner->run($import, $parent);
228
229         // Chapter checks
230         $this->assertEquals('Chapter A', $chapter->name);
231         $this->assertEquals($parent->id, $chapter->book_id);
232         $this->assertCount(1, $chapter->tags);
233         $firstChapterTag = $chapter->tags()->first();
234         $this->assertEquals('Reviewed', $firstChapterTag->name);
235         $this->assertEquals('2024', $firstChapterTag->value);
236         $this->assertCount(2, $chapter->pages);
237
238         // Page checks
239         /** @var Page $pageA */
240         $pageA = $chapter->pages->first();
241         $this->assertEquals('Page A', $pageA->name);
242         $this->assertCount(1, $pageA->tags);
243         $this->assertCount(1, $pageA->attachments);
244         $pageAImages = Image::where('uploaded_to', '=', $pageA->id)->whereIn('type', ['gallery', 'drawio'])->get();
245         $this->assertCount(1, $pageAImages);
246
247         // Reference checks
248         $attachment = $pageA->attachments->first();
249         $this->assertStringContainsString($pageA->getUrl(), $chapter->description_html);
250         $this->assertStringContainsString($chapter->getUrl(), $pageA->html);
251         $this->assertStringContainsString($pageAImages[0]->url, $pageA->html);
252         $this->assertStringContainsString($attachment->getUrl(), $pageA->html);
253
254         ZipTestHelper::deleteZipForImport($import);
255     }
256
257     public function test_page_import()
258     {
259         $testImagePath = $this->files->testFilePath('test-image.png');
260         $testFilePath = $this->files->testFilePath('test-file.txt');
261         $parent = $this->entities->chapter();
262
263         $import = ZipTestHelper::importFromData([], [
264             'page' => [
265                 'id' => 3,
266                 'name' => 'Page A',
267                 'priority' => 6,
268                 'html' => '<p><a href="[[bsexport:page:3]]">Link to self</a></p>
269 <p><a href="[[bsexport:image:2]]">Link to dog drawing</a></p>
270 <p><a href="[[bsexport:attachment:4]]">Link to text attachment</a></p>',
271                 'tags' => [
272                     ['name' => 'Unreviewed'],
273                 ],
274                 'attachments' => [
275                     [
276                         'id' => 4,
277                         'name' => 'Text attachment',
278                         'file' => 'file_attachment'
279                     ]
280                 ],
281                 'images' => [
282                     [
283                         'id' => 2,
284                         'name' => 'Dog Drawing',
285                         'type' => 'drawio',
286                         'file' => 'dog_image'
287                     ]
288                 ],
289             ],
290         ], [
291             'file_attachment'  => $testFilePath,
292             'dog_image' => $testImagePath,
293         ]);
294
295         $this->asAdmin();
296         /** @var Page $page */
297         $page = $this->runner->run($import, $parent);
298
299         // Page checks
300         $this->assertEquals('Page A', $page->name);
301         $this->assertCount(1, $page->tags);
302         $this->assertCount(1, $page->attachments);
303         $pageImages = Image::where('uploaded_to', '=', $page->id)->whereIn('type', ['gallery', 'drawio'])->get();
304         $this->assertCount(1, $pageImages);
305         $this->assertFileEquals($testImagePath, public_path($pageImages[0]->path));
306
307         // Reference checks
308         $this->assertStringContainsString($page->getUrl(), $page->html);
309         $this->assertStringContainsString($pageImages[0]->url, $page->html);
310         $this->assertStringContainsString($page->attachments->first()->getUrl(), $page->html);
311
312         ZipTestHelper::deleteZipForImport($import);
313     }
314
315     public function test_revert_cleans_up_uploaded_files()
316     {
317         $testImagePath = $this->files->testFilePath('test-image.png');
318         $testFilePath = $this->files->testFilePath('test-file.txt');
319         $parent = $this->entities->chapter();
320
321         $import = ZipTestHelper::importFromData([], [
322             'page' => [
323                 'name' => 'Page A',
324                 'html' => '<p>Hello</p>',
325                 'attachments' => [
326                     [
327                         'name' => 'Text attachment',
328                         'file' => 'file_attachment'
329                     ]
330                 ],
331                 'images' => [
332                     [
333                         'name' => 'Dog Image',
334                         'type' => 'gallery',
335                         'file' => 'dog_image'
336                     ]
337                 ],
338             ],
339         ], [
340             'file_attachment'  => $testFilePath,
341             'dog_image' => $testImagePath,
342         ]);
343
344         $this->asAdmin();
345         /** @var Page $page */
346         $page = $this->runner->run($import, $parent);
347
348         $attachment = $page->attachments->first();
349         $image = Image::query()->where('uploaded_to', '=', $page->id)->where('type', '=', 'gallery')->first();
350
351         $this->assertFileExists(public_path($image->path));
352         $this->assertFileExists(storage_path($attachment->path));
353
354         $this->runner->revertStoredFiles();
355
356         $this->assertFileDoesNotExist(public_path($image->path));
357         $this->assertFileDoesNotExist(storage_path($attachment->path));
358
359         ZipTestHelper::deleteZipForImport($import);
360     }
361 }