use BookStack\Exceptions\ImageUploadException;
use BookStack\Image;
-use BookStack\ImageRevision;
use BookStack\User;
+use DB;
use Exception;
use Intervention\Image\Exception\NotSupportedException;
use Intervention\Image\ImageManager;
protected $imageTool;
protected $cache;
protected $storageUrl;
+ protected $image;
/**
* ImageService constructor.
- * @param $imageTool
- * @param $fileSystem
- * @param $cache
+ * @param Image $image
+ * @param ImageManager $imageTool
+ * @param FileSystem $fileSystem
+ * @param Cache $cache
*/
- public function __construct(ImageManager $imageTool, FileSystem $fileSystem, Cache $cache)
+ public function __construct(Image $image, ImageManager $imageTool, FileSystem $fileSystem, Cache $cache)
{
+ $this->image = $image;
$this->imageTool = $imageTool;
$this->cache = $cache;
parent::__construct($fileSystem);
return $this->saveNew($name, $data, $type, $uploadedTo);
}
- /**
- * @param Image $image
- * @param string $base64Uri
- * @return Image
- * @throws ImageUploadException
- */
- public function updateImageFromBase64Uri(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]);
- return $this->update($image, $data);
- }
-
/**
* Gets an image from url and saves it to the database.
* @param $url
$secureUploads = setting('app-secure-images');
$imageName = str_replace(' ', '-', $imageName);
- if ($secureUploads) {
- $imageName = str_random(16) . '-' . $imageName;
- }
-
$imagePath = '/uploads/images/' . $type . '/' . Date('Y-m-M') . '/';
while ($storage->exists($imagePath . $imageName)) {
$imageName = str_random(3) . $imageName;
}
+
$fullPath = $imagePath . $imageName;
+ if ($secureUploads) {
+ $fullPath = $imagePath . str_random(16) . '-' . $imageName;
+ }
try {
$storage->put($fullPath, $imageData);
$imageDetails['updated_by'] = $userId;
}
- $image = (new Image());
+ $image = $this->image->newInstance();
$image->forceFill($imageDetails)->save();
return $image;
}
- /**
- * Update the content of an existing image.
- * Uploaded the new image content and creates a revision for the old image content.
- * @param Image $image
- * @param $imageData
- * @return Image
- * @throws ImageUploadException
- */
- private function update(Image $image, $imageData)
- {
- // Save image revision if not previously exists to ensure we always have
- // a reference to the image files being uploaded.
- if ($image->revisions()->count() === 0) {
- $this->saveImageRevision($image);
- }
-
- $pathInfo = pathinfo($image->path);
- $revisionCount = $image->revisionCount() + 1;
- $newFileName = preg_replace('/^(.+?)(-v\d+)?$/', '$1-v' . $revisionCount, $pathInfo['filename']);
-
- $image->path = str_replace_last($pathInfo['filename'], $newFileName, $image->path);
- $image->url = $this->getPublicUrl($image->path);
- $image->updated_by = user()->id;
-
- $storage = $this->getStorage();
-
- try {
- $storage->put($image->path, $imageData);
- $storage->setVisibility($image->path, 'public');
- $image->save();
- $this->saveImageRevision($image);
- } catch (Exception $e) {
- throw new ImageUploadException(trans('errors.path_not_writable', ['filePath' => $image->path]));
- }
- return $image;
- }
-
- /**
- * Save a new revision for an image.
- * @param Image $image
- * @return ImageRevision
- */
- protected function saveImageRevision(Image $image)
- {
- $revision = new ImageRevision();
- $revision->image_id = $image->id;
- $revision->path = $image->path;
- $revision->url = $image->url;
- $revision->created_by = user()->id;
- $revision->revision = $image->revisionCount() + 1;
- $revision->save();
- return $revision;
- }
/**
* Checks if the image is a gif. Returns true if it is, else false.
*/
public function destroy(Image $image)
{
- // Destroy image revisions
- foreach ($image->revisions as $revision) {
- $this->destroyImagesFromPath($revision->path);
- $revision->delete();
- }
-
- // Destroy main image
$this->destroyImagesFromPath($image->path);
$image->delete();
}
return $image;
}
+
+ /**
+ * Delete gallery and drawings that are not within HTML content of pages or page revisions.
+ * Checks based off of only the image name.
+ * Could be much improved to be more specific but kept it generic for now to be safe.
+ *
+ * Returns the path of the images that would be/have been deleted.
+ * @param bool $checkRevisions
+ * @param bool $dryRun
+ * @param array $types
+ * @return array
+ */
+ public function deleteUnusedImages($checkRevisions = true, $dryRun = true, $types = ['gallery', 'drawio'])
+ {
+ $types = array_intersect($types, ['gallery', 'drawio']);
+ $deletedPaths = [];
+
+ $this->image->newQuery()->whereIn('type', $types)
+ ->chunk(1000, function($images) use ($types, $checkRevisions, &$deletedPaths, $dryRun) {
+ foreach ($images as $image) {
+ $searchQuery = '%' . basename($image->path) . '%';
+ $inPage = DB::table('pages')
+ ->where('html', 'like', $searchQuery)->count() > 0;
+ $inRevision = false;
+ if ($checkRevisions) {
+ $inRevision = DB::table('page_revisions')
+ ->where('html', 'like', $searchQuery)->count() > 0;
+ }
+
+ if (!$inPage && !$inRevision) {
+ $deletedPaths[] = $image->path;
+ if (!$dryRun) {
+ $this->destroy($image);
+ }
+ }
+ }
+ });
+ return $deletedPaths;
+ }
+
/**
* Convert a image URI to a Base64 encoded string.
* Attempts to find locally via set storage method first.