1212use BookStack \Exceptions \ZipExportException ;
1313use BookStack \Exceptions \ZipImportException ;
1414use BookStack \Exports \Import ;
15+ use BookStack \Exports \ZipExports \Models \ZipExportAttachment ;
1516use BookStack \Exports \ZipExports \Models \ZipExportBook ;
1617use BookStack \Exports \ZipExports \Models \ZipExportChapter ;
18+ use BookStack \Exports \ZipExports \Models \ZipExportImage ;
1719use BookStack \Exports \ZipExports \Models \ZipExportPage ;
1820use BookStack \Exports \ZipExports \Models \ZipExportTag ;
21+ use BookStack \Uploads \Attachment ;
22+ use BookStack \Uploads \AttachmentService ;
1923use BookStack \Uploads \FileStorage ;
24+ use BookStack \Uploads \Image ;
2025use BookStack \Uploads \ImageService ;
2126use Illuminate \Http \UploadedFile ;
2227
2328class ZipImportRunner
2429{
25- protected array $ tempFilesToCleanup = []; // TODO
30+ protected array $ tempFilesToCleanup = [];
2631
2732 public function __construct (
2833 protected FileStorage $ storage ,
2934 protected PageRepo $ pageRepo ,
3035 protected ChapterRepo $ chapterRepo ,
3136 protected BookRepo $ bookRepo ,
3237 protected ImageService $ imageService ,
38+ protected AttachmentService $ attachmentService ,
3339 protected ZipImportReferences $ references ,
3440 ) {
3541 }
3642
3743 /**
44+ * Run the import.
45+ * Performs re-validation on zip, validation on parent provided, and permissions for importing
46+ * the planned content, before running the import process.
47+ * Returns the top-level entity item which was imported.
3848 * @throws ZipImportException
3949 */
40- public function run (Import $ import , ?Entity $ parent = null ): void
50+ public function run (Import $ import , ?Entity $ parent = null ): ? Entity
4151 {
4252 $ zipPath = $ this ->getZipPath ($ import );
4353 $ reader = new ZipExportReader ($ zipPath );
@@ -63,15 +73,40 @@ public function run(Import $import, ?Entity $parent = null): void
6373 }
6474
6575 $ this ->ensurePermissionsPermitImport ($ exportModel );
76+ $ entity = null ;
77+
78+ if ($ exportModel instanceof ZipExportBook) {
79+ $ entity = $ this ->importBook ($ exportModel , $ reader );
80+ } else if ($ exportModel instanceof ZipExportChapter) {
81+ $ entity = $ this ->importChapter ($ exportModel , $ parent , $ reader );
82+ } else if ($ exportModel instanceof ZipExportPage) {
83+ $ entity = $ this ->importPage ($ exportModel , $ parent , $ reader );
84+ }
6685
67- // TODO - Run import
6886 // TODO - In transaction?
6987 // TODO - Revert uploaded files if goes wrong
7088 // TODO - Attachments
7189 // TODO - Images
7290 // (Both listed/stored in references)
7391
7492 $ this ->references ->replaceReferences ();
93+
94+ $ reader ->close ();
95+ $ this ->cleanup ();
96+
97+ dd ('stop ' );
98+
99+ // TODO - Delete import/zip after import?
100+ // Do this in parent repo?
101+
102+ return $ entity ;
103+ }
104+
105+ protected function cleanup ()
106+ {
107+ foreach ($ this ->tempFilesToCleanup as $ file ) {
108+ unlink ($ file );
109+ }
75110 }
76111
77112 protected function importBook (ZipExportBook $ exportBook , ZipExportReader $ reader ): Book
@@ -83,17 +118,26 @@ protected function importBook(ZipExportBook $exportBook, ZipExportReader $reader
83118 'tags ' => $ this ->exportTagsToInputArray ($ exportBook ->tags ?? []),
84119 ]);
85120
86- // TODO - Parse/format description_html references
87-
88121 if ($ book ->cover ) {
89122 $ this ->references ->addImage ($ book ->cover , null );
90123 }
91124
92- // TODO - Pages
93- foreach ($ exportBook ->chapters as $ exportChapter ) {
94- $ this ->importChapter ($ exportChapter , $ book , $ reader );
125+ $ children = [
126+ ...$ exportBook ->chapters ,
127+ ...$ exportBook ->pages ,
128+ ];
129+
130+ usort ($ children , function (ZipExportPage |ZipExportChapter $ a , ZipExportPage |ZipExportChapter $ b ) {
131+ return ($ a ->priority ?? 0 ) - ($ b ->priority ?? 0 );
132+ });
133+
134+ foreach ($ children as $ child ) {
135+ if ($ child instanceof ZipExportChapter) {
136+ $ this ->importChapter ($ child , $ book , $ reader );
137+ } else if ($ child instanceof ZipExportPage) {
138+ $ this ->importPage ($ child , $ book , $ reader );
139+ }
95140 }
96- // TODO - Sort chapters/pages by order
97141
98142 $ this ->references ->addBook ($ book , $ exportBook );
99143
@@ -108,17 +152,14 @@ protected function importChapter(ZipExportChapter $exportChapter, Book $parent,
108152 'tags ' => $ this ->exportTagsToInputArray ($ exportChapter ->tags ?? []),
109153 ], $ parent );
110154
111- // TODO - Parse/format description_html references
112-
113155 $ exportPages = $ exportChapter ->pages ;
114156 usort ($ exportPages , function (ZipExportPage $ a , ZipExportPage $ b ) {
115157 return ($ a ->priority ?? 0 ) - ($ b ->priority ?? 0 );
116158 });
117159
118160 foreach ($ exportPages as $ exportPage ) {
119- //
161+ $ this -> importPage ( $ exportPage , $ chapter , $ reader );
120162 }
121- // TODO - Pages
122163
123164 $ this ->references ->addChapter ($ chapter , $ exportChapter );
124165
@@ -129,11 +170,13 @@ protected function importPage(ZipExportPage $exportPage, Book|Chapter $parent, Z
129170 {
130171 $ page = $ this ->pageRepo ->getNewDraftPage ($ parent );
131172
132- // TODO - Import attachments
133- // TODO - Add attachment references
134- // TODO - Import images
135- // TODO - Add image references
136- // TODO - Parse/format HTML
173+ foreach ($ exportPage ->attachments as $ exportAttachment ) {
174+ $ this ->importAttachment ($ exportAttachment , $ page , $ reader );
175+ }
176+
177+ foreach ($ exportPage ->images as $ exportImage ) {
178+ $ this ->importImage ($ exportImage , $ page , $ reader );
179+ }
137180
138181 $ this ->pageRepo ->publishDraft ($ page , [
139182 'name ' => $ exportPage ->name ,
@@ -147,6 +190,40 @@ protected function importPage(ZipExportPage $exportPage, Book|Chapter $parent, Z
147190 return $ page ;
148191 }
149192
193+ protected function importAttachment (ZipExportAttachment $ exportAttachment , Page $ page , ZipExportReader $ reader ): Attachment
194+ {
195+ if ($ exportAttachment ->file ) {
196+ $ file = $ this ->zipFileToUploadedFile ($ exportAttachment ->file , $ reader );
197+ $ attachment = $ this ->attachmentService ->saveNewUpload ($ file , $ page ->id );
198+ $ attachment ->name = $ exportAttachment ->name ;
199+ $ attachment ->save ();
200+ } else {
201+ $ attachment = $ this ->attachmentService ->saveNewFromLink (
202+ $ exportAttachment ->name ,
203+ $ exportAttachment ->link ?? '' ,
204+ $ page ->id ,
205+ );
206+ }
207+
208+ $ this ->references ->addAttachment ($ attachment , $ exportAttachment ->id );
209+
210+ return $ attachment ;
211+ }
212+
213+ protected function importImage (ZipExportImage $ exportImage , Page $ page , ZipExportReader $ reader ): Image
214+ {
215+ $ file = $ this ->zipFileToUploadedFile ($ exportImage ->file , $ reader );
216+ $ image = $ this ->imageService ->saveNewFromUpload (
217+ $ file ,
218+ $ exportImage ->type ,
219+ $ page ->id ,
220+ );
221+
222+ $ this ->references ->addImage ($ image , $ exportImage ->id );
223+
224+ return $ image ;
225+ }
226+
150227 protected function exportTagsToInputArray (array $ exportTags ): array
151228 {
152229 $ tags = [];
@@ -235,7 +312,7 @@ protected function ensurePermissionsPermitImport(ZipExportPage|ZipExportChapter|
235312 }
236313
237314 if (count ($ attachments ) > 0 ) {
238- if (userCan ('attachment-create-all ' )) {
315+ if (! userCan ('attachment-create-all ' )) {
239316 $ errors [] = 'You are lacking the required permissions to create attachments. ' ;
240317 }
241318 }
@@ -257,6 +334,8 @@ protected function getZipPath(Import $import): string
257334 stream_copy_to_stream ($ stream , $ tempFile );
258335 fclose ($ tempFile );
259336
337+ $ this ->tempFilesToCleanup [] = $ tempFilePath ;
338+
260339 return $ tempFilePath ;
261340 }
262341}
0 commit comments