mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-02-27 21:55:24 +08:00
Merge branch 'v0.30.x'
This commit is contained in:
commit
65b2c90522
14
.env.example
14
.env.example
@ -12,11 +12,13 @@
|
|||||||
APP_KEY=SomeRandomString
|
APP_KEY=SomeRandomString
|
||||||
|
|
||||||
# Application URL
|
# Application URL
|
||||||
# Remove the hash below and set a URL if using BookStack behind
|
|
||||||
# a proxy or if using a third-party authentication option.
|
|
||||||
# This must be the root URL that you want to host BookStack on.
|
# This must be the root URL that you want to host BookStack on.
|
||||||
# All URL's in BookStack will be generated using this value.
|
# All URLs in BookStack will be generated using this value
|
||||||
#APP_URL=https://example.com
|
# to ensure URLs generated are consistent and secure.
|
||||||
|
# If you change this in the future you may need to run a command
|
||||||
|
# to update stored URLs in the database. Command example:
|
||||||
|
# php artisan bookstack:update-url https://old.example.com https://new.example.com
|
||||||
|
APP_URL=https://example.com
|
||||||
|
|
||||||
# Database details
|
# Database details
|
||||||
DB_HOST=localhost
|
DB_HOST=localhost
|
||||||
@ -28,8 +30,8 @@ DB_PASSWORD=database_user_password
|
|||||||
# Can be 'smtp' or 'sendmail'
|
# Can be 'smtp' or 'sendmail'
|
||||||
MAIL_DRIVER=smtp
|
MAIL_DRIVER=smtp
|
||||||
|
|
||||||
# Mail sender options
|
# Mail sender details
|
||||||
MAIL_FROM_NAME=BookStack
|
MAIL_FROM_NAME="BookStack"
|
||||||
MAIL_FROM=bookstack@example.com
|
MAIL_FROM=bookstack@example.com
|
||||||
|
|
||||||
# SMTP mail options
|
# SMTP mail options
|
||||||
|
@ -42,13 +42,6 @@ return [
|
|||||||
'root' => storage_path(),
|
'root' => storage_path(),
|
||||||
],
|
],
|
||||||
|
|
||||||
'ftp' => [
|
|
||||||
'driver' => 'ftp',
|
|
||||||
'host' => 'ftp.example.com',
|
|
||||||
'username' => 'your-username',
|
|
||||||
'password' => 'your-password',
|
|
||||||
],
|
|
||||||
|
|
||||||
's3' => [
|
's3' => [
|
||||||
'driver' => 's3',
|
'driver' => 's3',
|
||||||
'key' => env('STORAGE_S3_KEY', 'your-key'),
|
'key' => env('STORAGE_S3_KEY', 'your-key'),
|
||||||
@ -59,16 +52,6 @@ return [
|
|||||||
'use_path_style_endpoint' => env('STORAGE_S3_ENDPOINT', null) !== null,
|
'use_path_style_endpoint' => env('STORAGE_S3_ENDPOINT', null) !== null,
|
||||||
],
|
],
|
||||||
|
|
||||||
'rackspace' => [
|
|
||||||
'driver' => 'rackspace',
|
|
||||||
'username' => 'your-username',
|
|
||||||
'key' => 'your-key',
|
|
||||||
'container' => 'your-container',
|
|
||||||
'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/',
|
|
||||||
'region' => 'IAD',
|
|
||||||
'url_type' => 'publicURL',
|
|
||||||
],
|
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -2,17 +2,29 @@
|
|||||||
|
|
||||||
use BookStack\Exceptions\FileUploadException;
|
use BookStack\Exceptions\FileUploadException;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Illuminate\Contracts\Filesystem\Factory as FileSystem;
|
||||||
|
use Illuminate\Contracts\Filesystem\Filesystem as FileSystemInstance;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
|
|
||||||
class AttachmentService extends UploadService
|
class AttachmentService
|
||||||
{
|
{
|
||||||
|
|
||||||
|
protected $fileSystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AttachmentService constructor.
|
||||||
|
*/
|
||||||
|
public function __construct(FileSystem $fileSystem)
|
||||||
|
{
|
||||||
|
$this->fileSystem = $fileSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the storage that will be used for storing files.
|
* Get the storage that will be used for storing files.
|
||||||
* @return \Illuminate\Contracts\Filesystem\Filesystem
|
|
||||||
*/
|
*/
|
||||||
protected function getStorage()
|
protected function getStorage(): FileSystemInstance
|
||||||
{
|
{
|
||||||
$storageType = config('filesystems.attachments');
|
$storageType = config('filesystems.attachments');
|
||||||
|
|
||||||
|
@ -4,16 +4,18 @@ use BookStack\Auth\User;
|
|||||||
use BookStack\Exceptions\HttpFetchException;
|
use BookStack\Exceptions\HttpFetchException;
|
||||||
use BookStack\Exceptions\ImageUploadException;
|
use BookStack\Exceptions\ImageUploadException;
|
||||||
use DB;
|
use DB;
|
||||||
|
use ErrorException;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Contracts\Cache\Repository as Cache;
|
use Illuminate\Contracts\Cache\Repository as Cache;
|
||||||
use Illuminate\Contracts\Filesystem\Factory as FileSystem;
|
use Illuminate\Contracts\Filesystem\Factory as FileSystem;
|
||||||
|
use Illuminate\Contracts\Filesystem\Filesystem as FileSystemInstance;
|
||||||
|
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Intervention\Image\Exception\NotSupportedException;
|
use Intervention\Image\Exception\NotSupportedException;
|
||||||
use Intervention\Image\ImageManager;
|
use Intervention\Image\ImageManager;
|
||||||
use phpDocumentor\Reflection\Types\Integer;
|
|
||||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
|
|
||||||
class ImageService extends UploadService
|
class ImageService
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $imageTool;
|
protected $imageTool;
|
||||||
@ -21,30 +23,24 @@ class ImageService extends UploadService
|
|||||||
protected $storageUrl;
|
protected $storageUrl;
|
||||||
protected $image;
|
protected $image;
|
||||||
protected $http;
|
protected $http;
|
||||||
|
protected $fileSystem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageService constructor.
|
* ImageService constructor.
|
||||||
* @param Image $image
|
|
||||||
* @param ImageManager $imageTool
|
|
||||||
* @param FileSystem $fileSystem
|
|
||||||
* @param Cache $cache
|
|
||||||
* @param HttpFetcher $http
|
|
||||||
*/
|
*/
|
||||||
public function __construct(Image $image, ImageManager $imageTool, FileSystem $fileSystem, Cache $cache, HttpFetcher $http)
|
public function __construct(Image $image, ImageManager $imageTool, FileSystem $fileSystem, Cache $cache, HttpFetcher $http)
|
||||||
{
|
{
|
||||||
$this->image = $image;
|
$this->image = $image;
|
||||||
$this->imageTool = $imageTool;
|
$this->imageTool = $imageTool;
|
||||||
|
$this->fileSystem = $fileSystem;
|
||||||
$this->cache = $cache;
|
$this->cache = $cache;
|
||||||
$this->http = $http;
|
$this->http = $http;
|
||||||
parent::__construct($fileSystem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the storage that will be used for storing images.
|
* Get the storage that will be used for storing images.
|
||||||
* @param string $type
|
|
||||||
* @return \Illuminate\Contracts\Filesystem\Filesystem
|
|
||||||
*/
|
*/
|
||||||
protected function getStorage($type = '')
|
protected function getStorage(string $type = ''): FileSystemInstance
|
||||||
{
|
{
|
||||||
$storageType = config('filesystems.images');
|
$storageType = config('filesystems.images');
|
||||||
|
|
||||||
@ -58,12 +54,6 @@ class ImageService extends UploadService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves a new image from an upload.
|
* Saves a new image from an upload.
|
||||||
* @param UploadedFile $uploadedFile
|
|
||||||
* @param string $type
|
|
||||||
* @param int $uploadedTo
|
|
||||||
* @param int|null $resizeWidth
|
|
||||||
* @param int|null $resizeHeight
|
|
||||||
* @param bool $keepRatio
|
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws ImageUploadException
|
* @throws ImageUploadException
|
||||||
*/
|
*/
|
||||||
@ -110,7 +100,7 @@ class ImageService extends UploadService
|
|||||||
* @param string $type
|
* @param string $type
|
||||||
* @param bool|string $imageName
|
* @param bool|string $imageName
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws \Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private function saveNewFromUrl($url, $type, $imageName = false)
|
private function saveNewFromUrl($url, $type, $imageName = false)
|
||||||
{
|
{
|
||||||
@ -118,7 +108,7 @@ class ImageService extends UploadService
|
|||||||
try {
|
try {
|
||||||
$imageData = $this->http->fetch($url);
|
$imageData = $this->http->fetch($url);
|
||||||
} catch (HttpFetchException $exception) {
|
} catch (HttpFetchException $exception) {
|
||||||
throw new \Exception(trans('errors.cannot_get_image_from_url', ['url' => $url]));
|
throw new Exception(trans('errors.cannot_get_image_from_url', ['url' => $url]));
|
||||||
}
|
}
|
||||||
return $this->saveNew($imageName, $imageData, $type);
|
return $this->saveNew($imageName, $imageData, $type);
|
||||||
}
|
}
|
||||||
@ -190,10 +180,8 @@ class ImageService extends UploadService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the image is a gif. Returns true if it is, else false.
|
* Checks if the image is a gif. Returns true if it is, else false.
|
||||||
* @param Image $image
|
|
||||||
* @return boolean
|
|
||||||
*/
|
*/
|
||||||
protected function isGif(Image $image)
|
protected function isGif(Image $image): bool
|
||||||
{
|
{
|
||||||
return strtolower(pathinfo($image->path, PATHINFO_EXTENSION)) === 'gif';
|
return strtolower(pathinfo($image->path, PATHINFO_EXTENSION)) === 'gif';
|
||||||
}
|
}
|
||||||
@ -253,7 +241,7 @@ class ImageService extends UploadService
|
|||||||
try {
|
try {
|
||||||
$thumb = $this->imageTool->make($imageData);
|
$thumb = $this->imageTool->make($imageData);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
if ($e instanceof \ErrorException || $e instanceof NotSupportedException) {
|
if ($e instanceof ErrorException || $e instanceof NotSupportedException) {
|
||||||
throw new ImageUploadException(trans('errors.cannot_create_thumbs'));
|
throw new ImageUploadException(trans('errors.cannot_create_thumbs'));
|
||||||
}
|
}
|
||||||
throw $e;
|
throw $e;
|
||||||
@ -281,11 +269,9 @@ class ImageService extends UploadService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the raw data content from an image.
|
* Get the raw data content from an image.
|
||||||
* @param Image $image
|
* @throws FileNotFoundException
|
||||||
* @return string
|
|
||||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
|
||||||
*/
|
*/
|
||||||
public function getImageData(Image $image)
|
public function getImageData(Image $image): string
|
||||||
{
|
{
|
||||||
$imagePath = $image->path;
|
$imagePath = $image->path;
|
||||||
$storage = $this->getStorage();
|
$storage = $this->getStorage();
|
||||||
@ -294,7 +280,6 @@ class ImageService extends UploadService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy an image along with its revisions, thumbnails and remaining folders.
|
* Destroy an image along with its revisions, thumbnails and remaining folders.
|
||||||
* @param Image $image
|
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function destroy(Image $image)
|
public function destroy(Image $image)
|
||||||
@ -324,7 +309,7 @@ class ImageService extends UploadService
|
|||||||
// Cleanup of empty folders
|
// Cleanup of empty folders
|
||||||
$foldersInvolved = array_merge([$imageFolder], $storage->directories($imageFolder));
|
$foldersInvolved = array_merge([$imageFolder], $storage->directories($imageFolder));
|
||||||
foreach ($foldersInvolved as $directory) {
|
foreach ($foldersInvolved as $directory) {
|
||||||
if ($this->isFolderEmpty($directory)) {
|
if ($this->isFolderEmpty($storage, $directory)) {
|
||||||
$storage->deleteDirectory($directory);
|
$storage->deleteDirectory($directory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -332,14 +317,21 @@ class ImageService extends UploadService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether or not a folder is empty.
|
||||||
|
*/
|
||||||
|
protected function isFolderEmpty(FileSystemInstance $storage, string $path): bool
|
||||||
|
{
|
||||||
|
$files = $storage->files($path);
|
||||||
|
$folders = $storage->directories($path);
|
||||||
|
return (count($files) === 0 && count($folders) === 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save an avatar image from an external service.
|
* Save an avatar image from an external service.
|
||||||
* @param \BookStack\Auth\User $user
|
|
||||||
* @param int $size
|
|
||||||
* @return Image
|
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function saveUserAvatar(User $user, $size = 500)
|
public function saveUserAvatar(User $user, int $size = 500): Image
|
||||||
{
|
{
|
||||||
$avatarUrl = $this->getAvatarUrl();
|
$avatarUrl = $this->getAvatarUrl();
|
||||||
$email = strtolower(trim($user->email));
|
$email = strtolower(trim($user->email));
|
||||||
@ -363,9 +355,8 @@ class ImageService extends UploadService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if fetching external avatars is enabled.
|
* Check if fetching external avatars is enabled.
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function avatarFetchEnabled()
|
public function avatarFetchEnabled(): bool
|
||||||
{
|
{
|
||||||
$fetchUrl = $this->getAvatarUrl();
|
$fetchUrl = $this->getAvatarUrl();
|
||||||
return is_string($fetchUrl) && strpos($fetchUrl, 'http') === 0;
|
return is_string($fetchUrl) && strpos($fetchUrl, 'http') === 0;
|
||||||
@ -427,38 +418,25 @@ class ImageService extends UploadService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a image URI to a Base64 encoded string.
|
* Convert a image URI to a Base64 encoded string.
|
||||||
* Attempts to find locally via set storage method first.
|
* Attempts to convert the URL to a system storage url then
|
||||||
* @param string $uri
|
* fetch the data from the disk or storage location.
|
||||||
* @return null|string
|
* Returns null if the image data cannot be fetched from storage.
|
||||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
* @throws FileNotFoundException
|
||||||
*/
|
*/
|
||||||
public function imageUriToBase64(string $uri)
|
public function imageUriToBase64(string $uri): ?string
|
||||||
{
|
{
|
||||||
$isLocal = strpos(trim($uri), 'http') !== 0;
|
$storagePath = $this->imageUrlToStoragePath($uri);
|
||||||
|
if (empty($uri) || is_null($storagePath)) {
|
||||||
// Attempt to find local files even if url not absolute
|
return null;
|
||||||
$base = url('/');
|
|
||||||
if (!$isLocal && strpos($uri, $base) === 0) {
|
|
||||||
$isLocal = true;
|
|
||||||
$uri = str_replace($base, '', $uri);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$imageData = null;
|
|
||||||
|
|
||||||
if ($isLocal) {
|
|
||||||
$uri = trim($uri, '/');
|
|
||||||
$storage = $this->getStorage();
|
$storage = $this->getStorage();
|
||||||
if ($storage->exists($uri)) {
|
$imageData = null;
|
||||||
$imageData = $storage->get($uri);
|
if ($storage->exists($storagePath)) {
|
||||||
}
|
$imageData = $storage->get($storagePath);
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
$imageData = $this->http->fetch($uri);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($imageData === null) {
|
if (is_null($imageData)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,11 +449,44 @@ class ImageService extends UploadService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a public facing url for an image by checking relevant environment variables.
|
* Get a storage path for the given image URL.
|
||||||
* @param string $filePath
|
* Ensures the path will start with "uploads/images".
|
||||||
* @return string
|
* Returns null if the url cannot be resolved to a local URL.
|
||||||
*/
|
*/
|
||||||
private function getPublicUrl($filePath)
|
private function imageUrlToStoragePath(string $url): ?string
|
||||||
|
{
|
||||||
|
$url = ltrim(trim($url), '/');
|
||||||
|
|
||||||
|
// Handle potential relative paths
|
||||||
|
$isRelative = strpos($url, 'http') !== 0;
|
||||||
|
if ($isRelative) {
|
||||||
|
if (strpos(strtolower($url), 'uploads/images') === 0) {
|
||||||
|
return trim($url, '/');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle local images based on paths on the same domain
|
||||||
|
$potentialHostPaths = [
|
||||||
|
url('uploads/images/'),
|
||||||
|
$this->getPublicUrl('/uploads/images/'),
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($potentialHostPaths as $potentialBasePath) {
|
||||||
|
$potentialBasePath = strtolower($potentialBasePath);
|
||||||
|
if (strpos(strtolower($url), $potentialBasePath) === 0) {
|
||||||
|
return 'uploads/images/' . trim(substr($url, strlen($potentialBasePath)), '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a public facing url for an image by checking relevant environment variables.
|
||||||
|
* If s3-style store is in use it will default to guessing a public bucket URL.
|
||||||
|
*/
|
||||||
|
private function getPublicUrl(string $filePath): string
|
||||||
{
|
{
|
||||||
if ($this->storageUrl === null) {
|
if ($this->storageUrl === null) {
|
||||||
$storageUrl = config('filesystems.url');
|
$storageUrl = config('filesystems.url');
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
<?php namespace BookStack\Uploads;
|
|
||||||
|
|
||||||
use Illuminate\Contracts\Filesystem\Factory as FileSystem;
|
|
||||||
use Illuminate\Contracts\Filesystem\Filesystem as FileSystemInstance;
|
|
||||||
|
|
||||||
abstract class UploadService
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var FileSystem
|
|
||||||
*/
|
|
||||||
protected $fileSystem;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FileService constructor.
|
|
||||||
* @param $fileSystem
|
|
||||||
*/
|
|
||||||
public function __construct(FileSystem $fileSystem)
|
|
||||||
{
|
|
||||||
$this->fileSystem = $fileSystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the storage that will be used for storing images.
|
|
||||||
* @return FileSystemInstance
|
|
||||||
*/
|
|
||||||
protected function getStorage()
|
|
||||||
{
|
|
||||||
$storageType = config('filesystems.default');
|
|
||||||
return $this->fileSystem->disk($storageType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether or not a folder is empty.
|
|
||||||
* @param $path
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
protected function isFolderEmpty($path)
|
|
||||||
{
|
|
||||||
$files = $this->getStorage()->files($path);
|
|
||||||
$folders = $this->getStorage()->directories($path);
|
|
||||||
return (count($files) === 0 && count($folders) === 0);
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use BookStack\Entities\Models\Chapter;
|
use BookStack\Entities\Models\Chapter;
|
||||||
use BookStack\Entities\Models\Page;
|
use BookStack\Entities\Models\Page;
|
||||||
use BookStack\Uploads\HttpFetcher;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
@ -154,14 +154,39 @@ class ExportTest extends TestCase
|
|||||||
public function test_page_export_sets_right_data_type_for_svg_embeds()
|
public function test_page_export_sets_right_data_type_for_svg_embeds()
|
||||||
{
|
{
|
||||||
$page = Page::first();
|
$page = Page::first();
|
||||||
$page->html = '<img src="http://example.com/image.svg">';
|
Storage::disk('local')->makeDirectory('uploads/images/gallery');
|
||||||
|
Storage::disk('local')->put('uploads/images/gallery/svg_test.svg', '<svg></svg>');
|
||||||
|
$page->html = '<img src="http://localhost/uploads/images/gallery/svg_test.svg">';
|
||||||
$page->save();
|
$page->save();
|
||||||
|
|
||||||
$this->asEditor();
|
$this->asEditor();
|
||||||
$this->mockHttpFetch('<svg></svg>');
|
|
||||||
$resp = $this->get($page->getUrl('/export/html'));
|
$resp = $this->get($page->getUrl('/export/html'));
|
||||||
|
Storage::disk('local')->delete('uploads/images/gallery/svg_test.svg');
|
||||||
|
|
||||||
$resp->assertStatus(200);
|
$resp->assertStatus(200);
|
||||||
$resp->assertSee('<img src="data:image/svg+xml;base64');
|
$resp->assertSee('<img src="data:image/svg+xml;base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_page_export_contained_html_image_fetches_only_run_when_url_points_to_image_upload_folder()
|
||||||
|
{
|
||||||
|
$page = Page::first();
|
||||||
|
$page->html = '<img src="http://localhost/uploads/images/gallery/svg_test.svg"/>'
|
||||||
|
."\n".'<img src="http://localhost/uploads/svg_test.svg"/>'
|
||||||
|
."\n".'<img src="/uploads/svg_test.svg"/>';
|
||||||
|
$storageDisk = Storage::disk('local');
|
||||||
|
$storageDisk->makeDirectory('uploads/images/gallery');
|
||||||
|
$storageDisk->put('uploads/images/gallery/svg_test.svg', '<svg>good</svg>');
|
||||||
|
$storageDisk->put('uploads/svg_test.svg', '<svg>bad</svg>');
|
||||||
|
$page->save();
|
||||||
|
|
||||||
|
$resp = $this->asEditor()->get($page->getUrl('/export/html'));
|
||||||
|
|
||||||
|
$storageDisk->delete('uploads/images/gallery/svg_test.svg');
|
||||||
|
$storageDisk->delete('uploads/svg_test.svg');
|
||||||
|
|
||||||
|
$resp->assertDontSee('http://localhost/uploads/images/gallery/svg_test.svg');
|
||||||
|
$resp->assertSee('http://localhost/uploads/svg_test.svg');
|
||||||
|
$resp->assertSee('src="/uploads/svg_test.svg"');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user