Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

draw.io integration #632

Merged
merged 11 commits into from
Jan 28, 2018
78 changes: 77 additions & 1 deletion app/Http/Controllers/ImageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ public function getGalleryFiltered($filter, $page = 0, Request $request)
* @param string $type
* @param Request $request
* @return \Illuminate\Http\JsonResponse
* @throws \Exception
*/
public function uploadByType($type, Request $request)
{
Expand All @@ -120,10 +121,14 @@ public function uploadByType($type, Request $request)
'file' => 'is_image'
]);

if (!$this->imageRepo->isValidType($type)) {
return $this->jsonError(trans('errors.image_upload_type_error'));
}

$imageUpload = $request->file('file');

try {
$uploadedTo = $request->filled('uploaded_to') ? $request->get('uploaded_to') : 0;
$uploadedTo = $request->get('uploaded_to', 0);
$image = $this->imageRepo->saveNew($imageUpload, $type, $uploadedTo);
} catch (ImageUploadException $e) {
return response($e->getMessage(), 500);
Expand All @@ -132,13 +137,82 @@ public function uploadByType($type, Request $request)
return response()->json($image);
}

/**
* Upload a drawing to the system.
* @param Request $request
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
*/
public function uploadDrawing(Request $request)
{
$this->validate($request, [
'image' => 'required|string',
'uploaded_to' => 'required|integer'
]);
$this->checkPermission('image-create-all');
$imageBase64Data = $request->get('image');

try {
$uploadedTo = $request->get('uploaded_to', 0);
$image = $this->imageRepo->saveDrawing($imageBase64Data, $uploadedTo);
} catch (ImageUploadException $e) {
return response($e->getMessage(), 500);
}

return response()->json($image);
}

/**
* Replace the data content of a drawing.
* @param string $id
* @param Request $request
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
*/
public function replaceDrawing(string $id, Request $request)
{
$this->validate($request, [
'image' => 'required|string'
]);
$this->checkPermission('image-create-all');

$imageBase64Data = $request->get('image');
$image = $this->imageRepo->getById($id);
$this->checkOwnablePermission('image-update', $image);

try {
$image = $this->imageRepo->replaceDrawingContent($image, $imageBase64Data);
} catch (ImageUploadException $e) {
return response($e->getMessage(), 500);
}

return response()->json($image);
}

/**
* Get the content of an image based64 encoded.
* @param $id
* @return \Illuminate\Http\JsonResponse|mixed
*/
public function getBase64Image($id)
{
$image = $this->imageRepo->getById($id);
$imageData = $this->imageRepo->getImageData($image);
if ($imageData === null) {
return $this->jsonError("Image data could not be found");
}
return response()->json([
'content' => base64_encode($imageData)
]);
}

/**
* Generate a sized thumbnail for an image.
* @param $id
* @param $width
* @param $height
* @param $crop
* @return \Illuminate\Http\JsonResponse
* @throws ImageUploadException
* @throws \Exception
*/
public function getThumbnail($id, $width, $height, $crop)
{
Expand All @@ -153,6 +227,8 @@ public function getThumbnail($id, $width, $height, $crop)
* @param integer $imageId
* @param Request $request
* @return \Illuminate\Http\JsonResponse
* @throws ImageUploadException
* @throws \Exception
*/
public function update($imageId, Request $request)
{
Expand Down
61 changes: 58 additions & 3 deletions app/Repos/ImageRepo.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
<?php namespace BookStack\Repos;


use BookStack\Image;
use BookStack\Page;
use BookStack\Services\ImageService;
use BookStack\Services\PermissionService;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Setting;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class ImageRepo
Expand Down Expand Up @@ -132,6 +129,8 @@ public function getGalleryFiltered($pagination = 0, $pageSize = 24, $filter, $pa
* @param string $type
* @param int $uploadedTo
* @return Image
* @throws \BookStack\Exceptions\ImageUploadException
* @throws \Exception
*/
public function saveNew(UploadedFile $uploadFile, $type, $uploadedTo = 0)
{
Expand All @@ -140,11 +139,39 @@ public function saveNew(UploadedFile $uploadFile, $type, $uploadedTo = 0)
return $image;
}

/**
* Save a drawing the the database;
* @param string $base64Uri
* @param int $uploadedTo
* @return Image
* @throws \BookStack\Exceptions\ImageUploadException
*/
public function saveDrawing(string $base64Uri, int $uploadedTo)
{
$name = 'Drawing-' . user()->getShortName(40) . '-' . strval(time()) . '.png';
$image = $this->imageService->saveNewFromBase64Uri($base64Uri, $name, 'drawio', $uploadedTo);
return $image;
}

/**
* Replace the image content of a drawing.
* @param Image $image
* @param string $base64Uri
* @return Image
* @throws \BookStack\Exceptions\ImageUploadException
*/
public function replaceDrawingContent(Image $image, string $base64Uri)
{
return $this->imageService->replaceImageDataFromBase64Uri($image, $base64Uri);
}

/**
* Update the details of an image via an array of properties.
* @param Image $image
* @param array $updateDetails
* @return Image
* @throws \BookStack\Exceptions\ImageUploadException
* @throws \Exception
*/
public function updateImageDetails(Image $image, $updateDetails)
{
Expand All @@ -170,6 +197,8 @@ public function destroyImage(Image $image)
/**
* Load thumbnails onto an image object.
* @param Image $image
* @throws \BookStack\Exceptions\ImageUploadException
* @throws \Exception
*/
private function loadThumbs(Image $image)
{
Expand All @@ -188,6 +217,8 @@ private function loadThumbs(Image $image)
* @param int $height
* @param bool $keepRatio
* @return string
* @throws \BookStack\Exceptions\ImageUploadException
* @throws \Exception
*/
public function getThumbnail(Image $image, $width = 220, $height = 220, $keepRatio = false)
{
Expand All @@ -199,5 +230,29 @@ public function getThumbnail(Image $image, $width = 220, $height = 220, $keepRat
}
}

/**
* Get the raw image data from an Image.
* @param Image $image
* @return null|string
*/
public function getImageData(Image $image)
{
try {
return $this->imageService->getImageData($image);
} catch (\Exception $exception) {
return null;
}
}

/**
* Check if the provided image type is valid.
* @param $type
* @return bool
*/
public function isValidType($type)
{
$validTypes = ['drawing', 'gallery', 'cover', 'system', 'user'];
return in_array($type, $validTypes);
}

}
57 changes: 57 additions & 0 deletions app/Services/ImageService.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,50 @@ public function saveNewFromUpload(UploadedFile $uploadedFile, $type, $uploadedTo
return $this->saveNew($imageName, $imageData, $type, $uploadedTo);
}

/**
* Save a new image from a uri-encoded base64 string of data.
* @param string $base64Uri
* @param string $name
* @param string $type
* @param int $uploadedTo
* @return Image
* @throws ImageUploadException
*/
public function saveNewFromBase64Uri(string $base64Uri, string $name, string $type, $uploadedTo = 0)
{
$splitData = explode(';base64,', $base64Uri);
if (count($splitData) < 2) {
throw new ImageUploadException("Invalid base64 image data provided");
}
$data = base64_decode($splitData[1]);
return $this->saveNew($name, $data, $type, $uploadedTo);
}

/**
* Replace the data for an image via a Base64 encoded string.
* @param Image $image
* @param string $base64Uri
* @return Image
* @throws ImageUploadException
*/
public function replaceImageDataFromBase64Uri(Image $image, string $base64Uri)
{
$splitData = explode(';base64,', $base64Uri);
if (count($splitData) < 2) {
throw new ImageUploadException("Invalid base64 image data provided");
}
$data = base64_decode($splitData[1]);
$storage = $this->getStorage();

try {
$storage->put($image->path, $data);
} catch (Exception $e) {
throw new ImageUploadException(trans('errors.path_not_writable', ['filePath' => $image->path]));
}

return $image;
}

/**
* Gets an image from url and saves it to the database.
* @param $url
Expand Down Expand Up @@ -175,6 +219,19 @@ public function getThumbnail(Image $image, $width = 220, $height = 220, $keepRat
return $this->getPublicUrl($thumbFilePath);
}

/**
* Get the raw data content from an image.
* @param Image $image
* @return string
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function getImageData(Image $image)
{
$imagePath = $this->getPath($image);
$storage = $this->getStorage();
return $storage->get($imagePath);
}

/**
* Destroys an Image object along with its files and thumbnails.
* @param Image $image
Expand Down
5 changes: 5 additions & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@
| to have a conventional place to find your various credentials.
|
*/

// Single option to disable non-auth external services such as Gravatar and Draw.io
'disable_services' => env('DISABLE_EXTERNAL_SERVICES', false),
'drawio' => env('DRAWIO', !env('DISABLE_EXTERNAL_SERVICES', false)),


'callback_url' => env('APP_URL', false),

'mailgun' => [
Expand Down
Loading