33namespace BookStack \Uploads \Controllers ;
44
55use BookStack \Entities \Queries \PageQueries ;
6+ use BookStack \Exceptions \NotFoundException ;
67use BookStack \Http \ApiController ;
78use BookStack \Permissions \Permission ;
89use BookStack \Uploads \Image ;
910use BookStack \Uploads \ImageRepo ;
1011use BookStack \Uploads \ImageResizer ;
12+ use BookStack \Uploads \ImageService ;
1113use Illuminate \Http \Request ;
1214
1315class ImageGalleryApiController extends ApiController
@@ -20,6 +22,7 @@ public function __construct(
2022 protected ImageRepo $ imageRepo ,
2123 protected ImageResizer $ imageResizer ,
2224 protected PageQueries $ pageQueries ,
25+ protected ImageService $ imageService ,
2326 ) {
2427 }
2528
@@ -32,6 +35,9 @@ protected function rules(): array
3235 'image ' => ['required ' , 'file ' , ...$ this ->getImageValidationRules ()],
3336 'name ' => ['string ' , 'max:180 ' ],
3437 ],
38+ 'readDataForUrl ' => [
39+ 'url ' => ['required ' , 'string ' , 'url ' ],
40+ ],
3541 'update ' => [
3642 'name ' => ['string ' , 'max:180 ' ],
3743 'image ' => ['file ' , ...$ this ->getImageValidationRules ()],
@@ -85,7 +91,8 @@ public function create(Request $request)
8591 * The "thumbs" response property contains links to scaled variants that BookStack may use in its UI.
8692 * The "content" response property provides HTML and Markdown content, in the format that BookStack
8793 * would typically use by default to add the image in page content, as a convenience.
88- * Actual image file data is not provided but can be fetched via the "url" response property.
94+ * Actual image file data is not provided but can be fetched via the "url" response property or by
95+ * using the "read-data" endpoint.
8996 */
9097 public function read (string $ id )
9198 {
@@ -94,6 +101,37 @@ public function read(string $id)
94101 return response ()->json ($ this ->formatForSingleResponse ($ image ));
95102 }
96103
104+ /**
105+ * Read the image file data for a single image in the system.
106+ * The returned response will be a stream of image data instead of a JSON response.
107+ */
108+ public function readData (string $ id )
109+ {
110+ $ image = Image::query ()->scopes (['visible ' ])->findOrFail ($ id );
111+
112+ return $ this ->imageService ->streamImageFromStorageResponse ('gallery ' , $ image ->path );
113+ }
114+
115+ /**
116+ * Read the image file data for a single image in the system, using the provided URL
117+ * to identify the image instead of its ID, which is provided as a "URL" query parameter.
118+ * The returned response will be a stream of image data instead of a JSON response.
119+ */
120+ public function readDataForUrl (Request $ request )
121+ {
122+ $ data = $ this ->validate ($ request , $ this ->rules ()['readDataForUrl ' ]);
123+ $ basePath = url ('/uploads/images/ ' );
124+ $ imagePath = str_replace ($ basePath , '' , $ data ['url ' ]);
125+
126+ if (!$ this ->imageService ->pathAccessible ($ imagePath )) {
127+ throw (new NotFoundException (trans ('errors.image_not_found ' )))
128+ ->setSubtitle (trans ('errors.image_not_found_subtitle ' ))
129+ ->setDetails (trans ('errors.image_not_found_details ' ));
130+ }
131+
132+ return $ this ->imageService ->streamImageFromStorageResponse ('gallery ' , $ imagePath );
133+ }
134+
97135 /**
98136 * Update the details of an existing image in the system.
99137 * Since "image" is expected to be a file, this needs to be a 'multipart/form-data' type request if providing a
0 commit comments