]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/Api/ImageGalleryApiController.php
Started Image API build
[bookstack] / app / Http / Controllers / Api / ImageGalleryApiController.php
1 <?php
2
3 namespace BookStack\Http\Controllers\Api;
4
5 use BookStack\Uploads\Image;
6 use BookStack\Uploads\ImageRepo;
7 use Illuminate\Http\Request;
8
9 class ImageGalleryApiController extends ApiController
10 {
11     protected array $fieldsToExpose = [
12         'id', 'name', 'url', 'path', 'type', 'uploaded_to', 'created_by', 'updated_by',  'created_at', 'updated_at',
13     ];
14
15     public function __construct(
16         protected ImageRepo $imageRepo
17     ) {
18     }
19
20     protected function rules(): array
21     {
22         return [
23             'create' => [
24                 'type'  => ['required', 'string', 'in:gallery,drawio'],
25                 'uploaded_to' => ['required', 'integer', 'exists:pages,id'],
26                 'image' => ['required', 'file', ...$this->getImageValidationRules()],
27                 'name'  => ['string', 'max:180'],
28             ],
29             'update' => [
30                 'name'  => ['string', 'max:180'],
31             ]
32         ];
33     }
34
35     /**
36      * Get a listing of gallery images and drawings in the system.
37      * Requires visibility of the content they're originally uploaded to.
38      */
39     public function list()
40     {
41         $images = Image::query()->scopes(['visible'])
42             ->select($this->fieldsToExpose)
43             ->whereIn('type', ['gallery', 'drawio']);
44
45         return $this->apiListingResponse($images, [
46             ...$this->fieldsToExpose
47         ]);
48     }
49
50     /**
51      * Create a new image in the system.
52      */
53     public function create(Request $request)
54     {
55         $data = $this->validate($request, $this->rules()['create']);
56
57         $image = $this->imageRepo->saveNew($data['image'], $data['type'], $data['uploaded_to']);
58
59         return response()->json($this->formatForSingleResponse($image));
60     }
61
62     /**
63      * View the details of a single image.
64      */
65     public function read(string $id)
66     {
67         $image = $this->imageRepo->getById($id);
68         $this->checkOwnablePermission('page-view', $image->getPage());
69
70         return response()->json($this->formatForSingleResponse($image));
71     }
72
73     /**
74      * Update an existing image in the system.
75      */
76     public function update(Request $request, string $id)
77     {
78         $data = $this->validate($request, $this->rules()['update']);
79         $image = $this->imageRepo->getById($id);
80         $this->checkOwnablePermission('page-view', $image->getPage());
81         $this->checkOwnablePermission('image-update', $image);
82
83         $this->imageRepo->updateImageDetails($image, $data);
84
85         return response()->json($this->formatForSingleResponse($image));
86     }
87
88     /**
89      * Delete an image from the system.
90      */
91     public function delete(string $id)
92     {
93         $image = $this->imageRepo->getById($id);
94         $this->checkOwnablePermission('page-view', $image->getPage());
95         $this->checkOwnablePermission('image-delete', $image);
96         $this->imageRepo->destroyImage($image);
97
98         return response('', 204);
99     }
100
101     /**
102      * Format the given image model for single-result display.
103      */
104     protected function formatForSingleResponse(Image $image): array
105     {
106         $this->imageRepo->loadThumbs($image);
107         $data = $image->getAttributes();
108         $data['created_by'] = $image->createdBy;
109         $data['updated_by'] = $image->updatedBy;
110         $data['content'] = [];
111
112         $escapedUrl = htmlentities($image->url);
113         $escapedName = htmlentities($image->name);
114         if ($image->type === 'drawio') {
115             $data['content']['html'] = "<div drawio-diagram=\"{$image->id}\"><img src=\"{$escapedUrl}\"></div>";
116             $data['content']['markdown'] = $data['content']['html'];
117         } else {
118             $escapedDisplayThumb = htmlentities($image->thumbs['display']);
119             $data['content']['html'] = "<a href=\"{$escapedUrl}\" target=\"_blank\"><img src=\"{$escapedDisplayThumb}\" alt=\"{$escapedName}\"></a>";
120             $mdEscapedName = str_replace(']', '', str_replace('[', '', $image->name));
121             $mdEscapedThumb = str_replace(']', '', str_replace('[', '', $image->thumbs['display']));
122             $data['content']['markdown'] = "![{$mdEscapedName}]({$mdEscapedThumb})";
123         }
124
125         return $data;
126     }
127 }