mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
parent
5d18e7df79
commit
da1a66abd3
@ -10,6 +10,7 @@ use BookStack\Entities\Models\Page;
|
||||
use BookStack\Model;
|
||||
use BookStack\Traits\HasCreatorAndUpdater;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
@ -29,6 +30,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
class Attachment extends Model
|
||||
{
|
||||
use HasCreatorAndUpdater;
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = ['name', 'order'];
|
||||
protected $hidden = ['path', 'page'];
|
||||
|
39
database/factories/Uploads/AttachmentFactory.php
Normal file
39
database/factories/Uploads/AttachmentFactory.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories\Uploads;
|
||||
|
||||
use BookStack\Auth\User;
|
||||
use BookStack\Entities\Models\Page;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\BookStack\Uploads\Attachment>
|
||||
*/
|
||||
class AttachmentFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = \BookStack\Uploads\Attachment::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->words(2, true),
|
||||
'path' => $this->faker->url(),
|
||||
'extension' => '',
|
||||
'external' => true,
|
||||
'uploaded_to' => Page::factory(),
|
||||
'created_by' => User::factory(),
|
||||
'updated_by' => User::factory(),
|
||||
'order' => 0,
|
||||
];
|
||||
}
|
||||
}
|
@ -6,12 +6,10 @@ use BookStack\Entities\Models\Book;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
use Tests\Uploads\UsesImages;
|
||||
|
||||
class BooksApiTest extends TestCase
|
||||
{
|
||||
use TestsApi;
|
||||
use UsesImages;
|
||||
|
||||
protected string $baseEndpoint = '/api/books';
|
||||
|
||||
@ -157,7 +155,7 @@ class BooksApiTest extends TestCase
|
||||
/** @var Book $book */
|
||||
$book = $this->entities->book();
|
||||
$this->assertNull($book->cover);
|
||||
$file = $this->getTestImage('image.png');
|
||||
$file = $this->files->uploadedImage('image.png');
|
||||
|
||||
// Ensure cover image can be set via API
|
||||
$resp = $this->call('PUT', $this->baseEndpoint . "/{$book->id}", [
|
||||
|
@ -7,12 +7,10 @@ use BookStack\Entities\Models\Bookshelf;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
use Tests\Uploads\UsesImages;
|
||||
|
||||
class ShelvesApiTest extends TestCase
|
||||
{
|
||||
use TestsApi;
|
||||
use UsesImages;
|
||||
|
||||
protected string $baseEndpoint = '/api/shelves';
|
||||
|
||||
@ -154,7 +152,7 @@ class ShelvesApiTest extends TestCase
|
||||
/** @var Book $shelf */
|
||||
$shelf = Bookshelf::visible()->first();
|
||||
$this->assertNull($shelf->cover);
|
||||
$file = $this->getTestImage('image.png');
|
||||
$file = $this->files->uploadedImage('image.png');
|
||||
|
||||
// Ensure cover image can be set via API
|
||||
$resp = $this->call('PUT', $this->baseEndpoint . "/{$shelf->id}", [
|
||||
|
@ -8,12 +8,9 @@ use BookStack\Entities\Models\Bookshelf;
|
||||
use BookStack\Uploads\Image;
|
||||
use Illuminate\Support\Str;
|
||||
use Tests\TestCase;
|
||||
use Tests\Uploads\UsesImages;
|
||||
|
||||
class BookShelfTest extends TestCase
|
||||
{
|
||||
use UsesImages;
|
||||
|
||||
public function test_shelves_shows_in_header_if_have_view_permissions()
|
||||
{
|
||||
$viewer = $this->users->viewer();
|
||||
@ -114,7 +111,7 @@ class BookShelfTest extends TestCase
|
||||
'description' => 'Test book description ' . Str::random(10),
|
||||
];
|
||||
|
||||
$imageFile = $this->getTestImage('shelf-test.png');
|
||||
$imageFile = $this->files->uploadedImage('shelf-test.png');
|
||||
$resp = $this->asEditor()->call('POST', '/shelves', $shelfInfo, [], ['image' => $imageFile]);
|
||||
$resp->assertRedirect();
|
||||
|
||||
|
@ -7,12 +7,9 @@ use BookStack\Entities\Models\BookChild;
|
||||
use BookStack\Entities\Models\Bookshelf;
|
||||
use BookStack\Entities\Repos\BookRepo;
|
||||
use Tests\TestCase;
|
||||
use Tests\Uploads\UsesImages;
|
||||
|
||||
class BookTest extends TestCase
|
||||
{
|
||||
use UsesImages;
|
||||
|
||||
public function test_create()
|
||||
{
|
||||
$book = Book::factory()->make([
|
||||
@ -333,7 +330,7 @@ class BookTest extends TestCase
|
||||
{
|
||||
$book = $this->entities->book();
|
||||
$bookRepo = $this->app->make(BookRepo::class);
|
||||
$coverImageFile = $this->getTestImage('cover.png');
|
||||
$coverImageFile = $this->files->uploadedImage('cover.png');
|
||||
$bookRepo->updateCoverImage($book, $coverImageFile);
|
||||
|
||||
$this->asEditor()->post($book->getUrl('/copy'), ['name' => 'My copy book']);
|
||||
|
@ -5,12 +5,9 @@ namespace Tests\Entity;
|
||||
use BookStack\Entities\Models\Page;
|
||||
use BookStack\Entities\Tools\PageContent;
|
||||
use Tests\TestCase;
|
||||
use Tests\Uploads\UsesImages;
|
||||
|
||||
class PageContentTest extends TestCase
|
||||
{
|
||||
use UsesImages;
|
||||
|
||||
protected $base64Jpeg = '/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=';
|
||||
|
||||
public function test_page_includes()
|
||||
@ -591,7 +588,7 @@ class PageContentTest extends TestCase
|
||||
$imageFile = public_path($imagePath);
|
||||
$this->assertEquals(base64_decode($this->base64Jpeg), file_get_contents($imageFile));
|
||||
|
||||
$this->deleteImage($imagePath);
|
||||
$this->files->deleteAtRelativePath($imagePath);
|
||||
}
|
||||
|
||||
public function test_base64_images_get_extracted_when_containing_whitespace()
|
||||
@ -615,7 +612,7 @@ class PageContentTest extends TestCase
|
||||
$imageFile = public_path($imagePath);
|
||||
$this->assertEquals(base64_decode($base64PngWithoutWhitespace), file_get_contents($imageFile));
|
||||
|
||||
$this->deleteImage($imagePath);
|
||||
$this->files->deleteAtRelativePath($imagePath);
|
||||
}
|
||||
|
||||
public function test_base64_images_within_html_blanked_if_not_supported_extension_for_extract()
|
||||
@ -659,7 +656,7 @@ class PageContentTest extends TestCase
|
||||
$imageFile = public_path($imagePath);
|
||||
$this->assertEquals(base64_decode($this->base64Jpeg), file_get_contents($imageFile));
|
||||
|
||||
$this->deleteImage($imagePath);
|
||||
$this->files->deleteAtRelativePath($imagePath);
|
||||
}
|
||||
|
||||
public function test_markdown_base64_extract_not_limited_by_pcre_limits()
|
||||
@ -690,7 +687,7 @@ class PageContentTest extends TestCase
|
||||
$imageFile = public_path($imagePath);
|
||||
$this->assertEquals($content, file_get_contents($imageFile));
|
||||
|
||||
$this->deleteImage($imagePath);
|
||||
$this->files->deleteAtRelativePath($imagePath);
|
||||
ini_set('pcre.backtrack_limit', $pcreBacktrackLimit);
|
||||
ini_set('pcre.recursion_limit', $pcreRecursionLimit);
|
||||
}
|
||||
|
153
tests/Helpers/FileProvider.php
Normal file
153
tests/Helpers/FileProvider.php
Normal file
@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Helpers;
|
||||
|
||||
use BookStack\Entities\Models\Page;
|
||||
use BookStack\Uploads\Attachment;
|
||||
use BookStack\Uploads\AttachmentService;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Testing\TestResponse;
|
||||
use stdClass;
|
||||
use Tests\TestCase;
|
||||
|
||||
class FileProvider
|
||||
{
|
||||
/**
|
||||
* Get the path to a file in the test-data-directory.
|
||||
*/
|
||||
public function testFilePath(string $fileName): string
|
||||
{
|
||||
return base_path('tests/test-data/' . $fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new temporary image file using the given name,
|
||||
* with the content decoded from the given bas64 file name.
|
||||
* Is generally used for testing sketchy files that could trip AV.
|
||||
*/
|
||||
public function imageFromBase64File(string $base64FileName, string $imageFileName): UploadedFile
|
||||
{
|
||||
$imagePath = implode(DIRECTORY_SEPARATOR, [sys_get_temp_dir(), $imageFileName]);
|
||||
$base64FilePath = $this->testFilePath($base64FileName);
|
||||
$data = file_get_contents($base64FilePath);
|
||||
$decoded = base64_decode($data);
|
||||
file_put_contents($imagePath, $decoded);
|
||||
|
||||
return new UploadedFile($imagePath, $imageFileName, 'image/png', null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a test image UploadedFile instance, that can be uploaded via test requests.
|
||||
*/
|
||||
public function uploadedImage(string $fileName, string $testDataFileName = ''): UploadedFile
|
||||
{
|
||||
return new UploadedFile($this->testFilePath($testDataFileName ?: 'test-image.png'), $fileName, 'image/png', null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a test txt UploadedFile instance, that can be uploaded via test requests.
|
||||
*/
|
||||
public function uploadedTextFile(string $fileName): UploadedFile
|
||||
{
|
||||
return new UploadedFile($this->testFilePath('test-file.txt'), $fileName, 'text/plain', null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw data for a PNG image test file.
|
||||
*/
|
||||
public function pngImageData(): string
|
||||
{
|
||||
return file_get_contents($this->testFilePath('test-image.png'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expected relative path for an uploaded image of the given type and filename.
|
||||
*/
|
||||
public function expectedImagePath(string $imageType, string $fileName): string
|
||||
{
|
||||
return '/uploads/images/' . $imageType . '/' . date('Y-m') . '/' . $fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an image gallery upload request with the given name.
|
||||
*/
|
||||
public function uploadGalleryImage(TestCase $case, string $name, int $uploadedTo = 0, string $contentType = 'image/png', string $testDataFileName = ''): TestResponse
|
||||
{
|
||||
$file = $this->uploadedImage($name, $testDataFileName);
|
||||
|
||||
return $case->call('POST', '/images/gallery', ['uploaded_to' => $uploadedTo], [], ['file' => $file], ['CONTENT_TYPE' => $contentType]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a new gallery image and return a set of details about the image,
|
||||
* including the json decoded response of the upload.
|
||||
* Ensures the upload succeeds.
|
||||
*
|
||||
* @return array{name: string, path: string, page: Page, response: stdClass}
|
||||
*/
|
||||
public function uploadGalleryImageToPage(TestCase $case, Page $page, string $testDataFileName = ''): array
|
||||
{
|
||||
$imageName = $testDataFileName ?: 'first-image.png';
|
||||
$relPath = $this->expectedImagePath('gallery', $imageName);
|
||||
$this->deleteAtRelativePath($relPath);
|
||||
|
||||
$upload = $this->uploadGalleryImage($case, $imageName, $page->id, 'image/png', $testDataFileName);
|
||||
$upload->assertStatus(200);
|
||||
|
||||
return [
|
||||
'name' => $imageName,
|
||||
'path' => $relPath,
|
||||
'page' => $page,
|
||||
'response' => json_decode($upload->getContent()),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads an attachment file with the given name.
|
||||
*/
|
||||
public function uploadAttachmentFile(TestCase $case, string $name, int $uploadedTo = 0): TestResponse
|
||||
{
|
||||
$file = $this->uploadedTextFile($name);
|
||||
|
||||
return $case->call('POST', '/attachments/upload', ['uploaded_to' => $uploadedTo], [], ['file' => $file], []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a new attachment from the given raw data of the given type, to the given page.
|
||||
* Returns the attachment
|
||||
*/
|
||||
public function uploadAttachmentDataToPage(TestCase $case, Page $page, string $filename, string $content, string $mimeType): Attachment
|
||||
{
|
||||
$file = tmpfile();
|
||||
$filePath = stream_get_meta_data($file)['uri'];
|
||||
file_put_contents($filePath, $content);
|
||||
$upload = new UploadedFile($filePath, $filename, $mimeType, null, true);
|
||||
|
||||
$case->call('POST', '/attachments/upload', ['uploaded_to' => $page->id], [], ['file' => $upload], []);
|
||||
|
||||
return $page->attachments()->where('uploaded_to', '=', $page->id)->latest()->firstOrFail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an uploaded image.
|
||||
*/
|
||||
public function deleteAtRelativePath(string $path): void
|
||||
{
|
||||
$fullPath = public_path($path);
|
||||
if (file_exists($fullPath)) {
|
||||
unlink($fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all uploaded files.
|
||||
* To assist with cleanup.
|
||||
*/
|
||||
public function deleteAllAttachmentFiles(): void
|
||||
{
|
||||
$fileService = app()->make(AttachmentService::class);
|
||||
foreach (Attachment::all() as $file) {
|
||||
$fileService->deleteFile($file);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,12 +6,9 @@ use BookStack\Entities\Repos\BaseRepo;
|
||||
use BookStack\Entities\Repos\BookRepo;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Testing\TestResponse;
|
||||
use Tests\Uploads\UsesImages;
|
||||
|
||||
class OpenGraphTest extends TestCase
|
||||
{
|
||||
use UsesImages;
|
||||
|
||||
public function test_page_tags()
|
||||
{
|
||||
$page = $this->entities->page();
|
||||
@ -47,7 +44,7 @@ class OpenGraphTest extends TestCase
|
||||
|
||||
// Test image set if image has cover image
|
||||
$bookRepo = app(BookRepo::class);
|
||||
$bookRepo->updateCoverImage($book, $this->getTestImage('image.png'));
|
||||
$bookRepo->updateCoverImage($book, $this->files->uploadedImage('image.png'));
|
||||
$resp = $this->asEditor()->get($book->getUrl());
|
||||
$tags = $this->getOpenGraphTags($resp);
|
||||
|
||||
@ -67,7 +64,7 @@ class OpenGraphTest extends TestCase
|
||||
|
||||
// Test image set if image has cover image
|
||||
$baseRepo = app(BaseRepo::class);
|
||||
$baseRepo->updateCoverImage($shelf, $this->getTestImage('image.png'));
|
||||
$baseRepo->updateCoverImage($shelf, $this->files->uploadedImage('image.png'));
|
||||
$resp = $this->asEditor()->get($shelf->getUrl());
|
||||
$tags = $this->getOpenGraphTags($resp);
|
||||
|
||||
|
@ -3,12 +3,9 @@
|
||||
namespace Tests\Settings;
|
||||
|
||||
use Tests\TestCase;
|
||||
use Tests\Uploads\UsesImages;
|
||||
|
||||
class SettingsTest extends TestCase
|
||||
{
|
||||
use UsesImages;
|
||||
|
||||
public function test_settings_endpoint_redirects_to_settings_view()
|
||||
{
|
||||
$resp = $this->asAdmin()->get('/settings');
|
||||
@ -47,7 +44,7 @@ class SettingsTest extends TestCase
|
||||
public function test_updating_and_removing_app_icon()
|
||||
{
|
||||
$this->asAdmin();
|
||||
$galleryFile = $this->getTestImage('my-app-icon.png');
|
||||
$galleryFile = $this->files->uploadedImage('my-app-icon.png');
|
||||
$expectedPath = public_path('uploads/images/system/' . date('Y-m') . '/my-app-icon.png');
|
||||
|
||||
$this->assertFalse(setting()->get('app-icon'));
|
||||
|
@ -23,6 +23,7 @@ use Monolog\Logger;
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Ssddanbrown\AssertHtml\TestsHtml;
|
||||
use Tests\Helpers\EntityProvider;
|
||||
use Tests\Helpers\FileProvider;
|
||||
use Tests\Helpers\PermissionsProvider;
|
||||
use Tests\Helpers\TestServiceProvider;
|
||||
use Tests\Helpers\UserRoleProvider;
|
||||
@ -36,12 +37,14 @@ abstract class TestCase extends BaseTestCase
|
||||
protected EntityProvider $entities;
|
||||
protected UserRoleProvider $users;
|
||||
protected PermissionsProvider $permissions;
|
||||
protected FileProvider $files;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->entities = new EntityProvider();
|
||||
$this->users = new UserRoleProvider();
|
||||
$this->permissions = new PermissionsProvider($this->users);
|
||||
$this->files = new FileProvider();
|
||||
|
||||
parent::setUp();
|
||||
|
||||
|
@ -6,71 +6,10 @@ use BookStack\Entities\Models\Page;
|
||||
use BookStack\Entities\Repos\PageRepo;
|
||||
use BookStack\Entities\Tools\TrashCan;
|
||||
use BookStack\Uploads\Attachment;
|
||||
use BookStack\Uploads\AttachmentService;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AttachmentTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Get a test file that can be uploaded.
|
||||
*/
|
||||
protected function getTestFile(string $fileName): UploadedFile
|
||||
{
|
||||
return new UploadedFile(base_path('tests/test-data/test-file.txt'), $fileName, 'text/plain', null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads a file with the given name.
|
||||
*/
|
||||
protected function uploadFile(string $name, int $uploadedTo = 0): \Illuminate\Testing\TestResponse
|
||||
{
|
||||
$file = $this->getTestFile($name);
|
||||
|
||||
return $this->call('POST', '/attachments/upload', ['uploaded_to' => $uploadedTo], [], ['file' => $file], []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new attachment.
|
||||
*/
|
||||
protected function createAttachment(Page $page): Attachment
|
||||
{
|
||||
$this->post('attachments/link', [
|
||||
'attachment_link_url' => 'https://example.com',
|
||||
'attachment_link_name' => 'Example Attachment Link',
|
||||
'attachment_link_uploaded_to' => $page->id,
|
||||
]);
|
||||
|
||||
return Attachment::query()->latest()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new upload attachment from the given data.
|
||||
*/
|
||||
protected function createUploadAttachment(Page $page, string $filename, string $content, string $mimeType): Attachment
|
||||
{
|
||||
$file = tmpfile();
|
||||
$filePath = stream_get_meta_data($file)['uri'];
|
||||
file_put_contents($filePath, $content);
|
||||
$upload = new UploadedFile($filePath, $filename, $mimeType, null, true);
|
||||
|
||||
$this->call('POST', '/attachments/upload', ['uploaded_to' => $page->id], [], ['file' => $upload], []);
|
||||
|
||||
return $page->attachments()->latest()->firstOrFail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all uploaded files.
|
||||
* To assist with cleanup.
|
||||
*/
|
||||
protected function deleteUploads()
|
||||
{
|
||||
$fileService = $this->app->make(AttachmentService::class);
|
||||
foreach (Attachment::all() as $file) {
|
||||
$fileService->deleteFile($file);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_file_upload()
|
||||
{
|
||||
$page = $this->entities->page();
|
||||
@ -87,7 +26,7 @@ class AttachmentTest extends TestCase
|
||||
'updated_by' => $admin->id,
|
||||
];
|
||||
|
||||
$upload = $this->uploadFile($fileName, $page->id);
|
||||
$upload = $this->files->uploadAttachmentFile($this, $fileName, $page->id);
|
||||
$upload->assertStatus(200);
|
||||
|
||||
$attachment = Attachment::query()->orderBy('id', 'desc')->first();
|
||||
@ -96,7 +35,7 @@ class AttachmentTest extends TestCase
|
||||
$expectedResp['path'] = $attachment->path;
|
||||
$this->assertDatabaseHas('attachments', $expectedResp);
|
||||
|
||||
$this->deleteUploads();
|
||||
$this->files->deleteAllAttachmentFiles();
|
||||
}
|
||||
|
||||
public function test_file_upload_does_not_use_filename()
|
||||
@ -104,13 +43,14 @@ class AttachmentTest extends TestCase
|
||||
$page = $this->entities->page();
|
||||
$fileName = 'upload_test_file.txt';
|
||||
|
||||
$upload = $this->asAdmin()->uploadFile($fileName, $page->id);
|
||||
$this->asAdmin();
|
||||
$upload = $this->files->uploadAttachmentFile($this, $fileName, $page->id);
|
||||
$upload->assertStatus(200);
|
||||
|
||||
$attachment = Attachment::query()->orderBy('id', 'desc')->first();
|
||||
$this->assertStringNotContainsString($fileName, $attachment->path);
|
||||
$this->assertStringEndsWith('-txt', $attachment->path);
|
||||
$this->deleteUploads();
|
||||
$this->files->deleteAllAttachmentFiles();
|
||||
}
|
||||
|
||||
public function test_file_display_and_access()
|
||||
@ -119,7 +59,7 @@ class AttachmentTest extends TestCase
|
||||
$this->asAdmin();
|
||||
$fileName = 'upload_test_file.txt';
|
||||
|
||||
$upload = $this->uploadFile($fileName, $page->id);
|
||||
$upload = $this->files->uploadAttachmentFile($this, $fileName, $page->id);
|
||||
$upload->assertStatus(200);
|
||||
$attachment = Attachment::orderBy('id', 'desc')->take(1)->first();
|
||||
|
||||
@ -131,7 +71,7 @@ class AttachmentTest extends TestCase
|
||||
$content = $attachmentGet->streamedContent();
|
||||
$this->assertStringContainsString('Hi, This is a test file for testing the upload process.', $content);
|
||||
|
||||
$this->deleteUploads();
|
||||
$this->files->deleteAllAttachmentFiles();
|
||||
}
|
||||
|
||||
public function test_attaching_link_to_page()
|
||||
@ -168,7 +108,7 @@ class AttachmentTest extends TestCase
|
||||
$attachmentGet = $this->get($attachment->getUrl());
|
||||
$attachmentGet->assertRedirect('https://example.com');
|
||||
|
||||
$this->deleteUploads();
|
||||
$this->files->deleteAllAttachmentFiles();
|
||||
}
|
||||
|
||||
public function test_attachment_updating()
|
||||
@ -176,7 +116,7 @@ class AttachmentTest extends TestCase
|
||||
$page = $this->entities->page();
|
||||
$this->asAdmin();
|
||||
|
||||
$attachment = $this->createAttachment($page);
|
||||
$attachment = Attachment::factory()->create(['uploaded_to' => $page->id]);
|
||||
$update = $this->call('PUT', 'attachments/' . $attachment->id, [
|
||||
'attachment_edit_name' => 'My new attachment name',
|
||||
'attachment_edit_url' => 'https://test.example.com',
|
||||
@ -192,7 +132,7 @@ class AttachmentTest extends TestCase
|
||||
$update->assertStatus(200);
|
||||
$this->assertDatabaseHas('attachments', $expectedData);
|
||||
|
||||
$this->deleteUploads();
|
||||
$this->files->deleteAllAttachmentFiles();
|
||||
}
|
||||
|
||||
public function test_file_deletion()
|
||||
@ -200,7 +140,7 @@ class AttachmentTest extends TestCase
|
||||
$page = $this->entities->page();
|
||||
$this->asAdmin();
|
||||
$fileName = 'deletion_test.txt';
|
||||
$this->uploadFile($fileName, $page->id);
|
||||
$this->files->uploadAttachmentFile($this, $fileName, $page->id);
|
||||
|
||||
$attachment = Attachment::query()->orderBy('id', 'desc')->first();
|
||||
$filePath = storage_path($attachment->path);
|
||||
@ -214,7 +154,7 @@ class AttachmentTest extends TestCase
|
||||
]);
|
||||
$this->assertFalse(file_exists($filePath), 'File at path ' . $filePath . ' was not deleted as expected');
|
||||
|
||||
$this->deleteUploads();
|
||||
$this->files->deleteAllAttachmentFiles();
|
||||
}
|
||||
|
||||
public function test_attachment_deletion_on_page_deletion()
|
||||
@ -222,7 +162,7 @@ class AttachmentTest extends TestCase
|
||||
$page = $this->entities->page();
|
||||
$this->asAdmin();
|
||||
$fileName = 'deletion_test.txt';
|
||||
$this->uploadFile($fileName, $page->id);
|
||||
$this->files->uploadAttachmentFile($this, $fileName, $page->id);
|
||||
|
||||
$attachment = Attachment::query()->orderBy('id', 'desc')->first();
|
||||
$filePath = storage_path($attachment->path);
|
||||
@ -240,7 +180,7 @@ class AttachmentTest extends TestCase
|
||||
]);
|
||||
$this->assertFalse(file_exists($filePath), 'File at path ' . $filePath . ' was not deleted as expected');
|
||||
|
||||
$this->deleteUploads();
|
||||
$this->files->deleteAllAttachmentFiles();
|
||||
}
|
||||
|
||||
public function test_attachment_access_without_permission_shows_404()
|
||||
@ -250,7 +190,7 @@ class AttachmentTest extends TestCase
|
||||
$page = $this->entities->page(); /** @var Page $page */
|
||||
$this->actingAs($admin);
|
||||
$fileName = 'permission_test.txt';
|
||||
$this->uploadFile($fileName, $page->id);
|
||||
$this->files->uploadAttachmentFile($this, $fileName, $page->id);
|
||||
$attachment = Attachment::orderBy('id', 'desc')->take(1)->first();
|
||||
|
||||
$this->permissions->setEntityPermissions($page, [], []);
|
||||
@ -260,7 +200,7 @@ class AttachmentTest extends TestCase
|
||||
$attachmentGet->assertStatus(404);
|
||||
$attachmentGet->assertSee('Attachment not found');
|
||||
|
||||
$this->deleteUploads();
|
||||
$this->files->deleteAllAttachmentFiles();
|
||||
}
|
||||
|
||||
public function test_data_and_js_links_cannot_be_attached_to_a_page()
|
||||
@ -290,7 +230,7 @@ class AttachmentTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
$attachment = $this->createAttachment($page);
|
||||
$attachment = Attachment::factory()->create(['uploaded_to' => $page->id]);
|
||||
|
||||
foreach ($badLinks as $badLink) {
|
||||
$linkReq = $this->put('attachments/' . $attachment->id, [
|
||||
@ -310,7 +250,7 @@ class AttachmentTest extends TestCase
|
||||
$this->asAdmin();
|
||||
$fileName = 'upload_test_file.txt';
|
||||
|
||||
$upload = $this->uploadFile($fileName, $page->id);
|
||||
$upload = $this->files->uploadAttachmentFile($this, $fileName, $page->id);
|
||||
$upload->assertStatus(200);
|
||||
$attachment = Attachment::query()->orderBy('id', 'desc')->take(1)->first();
|
||||
|
||||
@ -320,7 +260,7 @@ class AttachmentTest extends TestCase
|
||||
$attachmentGet->assertHeader('Content-Disposition', 'inline; filename="upload_test_file.txt"');
|
||||
$attachmentGet->assertHeader('X-Content-Type-Options', 'nosniff');
|
||||
|
||||
$this->deleteUploads();
|
||||
$this->files->deleteAllAttachmentFiles();
|
||||
}
|
||||
|
||||
public function test_html_file_access_with_open_forces_plain_content_type()
|
||||
@ -328,14 +268,14 @@ class AttachmentTest extends TestCase
|
||||
$page = $this->entities->page();
|
||||
$this->asAdmin();
|
||||
|
||||
$attachment = $this->createUploadAttachment($page, 'test_file.html', '<html></html><p>testing</p>', 'text/html');
|
||||
$attachment = $this->files->uploadAttachmentDataToPage($this, $page, 'test_file.html', '<html></html><p>testing</p>', 'text/html');
|
||||
|
||||
$attachmentGet = $this->get($attachment->getUrl(true));
|
||||
// http-foundation/Response does some 'fixing' of responses to add charsets to text responses.
|
||||
$attachmentGet->assertHeader('Content-Type', 'text/plain; charset=UTF-8');
|
||||
$attachmentGet->assertHeader('Content-Disposition', 'inline; filename="test_file.html"');
|
||||
|
||||
$this->deleteUploads();
|
||||
$this->files->deleteAllAttachmentFiles();
|
||||
}
|
||||
|
||||
public function test_file_upload_works_when_local_secure_restricted_is_in_use()
|
||||
@ -345,11 +285,12 @@ class AttachmentTest extends TestCase
|
||||
$page = $this->entities->page();
|
||||
$fileName = 'upload_test_file.txt';
|
||||
|
||||
$upload = $this->asAdmin()->uploadFile($fileName, $page->id);
|
||||
$this->asAdmin();
|
||||
$upload = $this->files->uploadAttachmentFile($this, $fileName, $page->id);
|
||||
$upload->assertStatus(200);
|
||||
|
||||
$attachment = Attachment::query()->orderBy('id', 'desc')->where('uploaded_to', '=', $page->id)->first();
|
||||
$this->assertFileExists(storage_path($attachment->path));
|
||||
$this->deleteUploads();
|
||||
$this->files->deleteAllAttachmentFiles();
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,6 @@ use Tests\TestCase;
|
||||
|
||||
class AvatarTest extends TestCase
|
||||
{
|
||||
use UsesImages;
|
||||
|
||||
protected function createUserRequest($user): User
|
||||
{
|
||||
$this->asAdmin()->post('/settings/users/create', [
|
||||
@ -29,12 +27,12 @@ class AvatarTest extends TestCase
|
||||
|
||||
$http->shouldReceive('fetch')
|
||||
->once()->with($url)
|
||||
->andReturn($this->getTestImageContent());
|
||||
->andReturn($this->files->pngImageData());
|
||||
}
|
||||
|
||||
protected function deleteUserImage(User $user)
|
||||
{
|
||||
$this->deleteImage($user->avatar->path);
|
||||
$this->files->deleteAtRelativePath($user->avatar->path);
|
||||
}
|
||||
|
||||
public function test_gravatar_fetched_on_user_create()
|
||||
|
@ -2,21 +2,18 @@
|
||||
|
||||
namespace Tests\Uploads;
|
||||
|
||||
use BookStack\Entities\Models\Page;
|
||||
use BookStack\Uploads\Image;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DrawioTest extends TestCase
|
||||
{
|
||||
use UsesImages;
|
||||
|
||||
public function test_get_image_as_base64()
|
||||
{
|
||||
$page = $this->entities->page();
|
||||
$this->asAdmin();
|
||||
$imageName = 'first-image.png';
|
||||
|
||||
$this->uploadImage($imageName, $page->id);
|
||||
$this->files->uploadGalleryImage($this, $imageName, $page->id);
|
||||
/** @var Image $image */
|
||||
$image = Image::query()->first();
|
||||
$image->type = 'drawio';
|
||||
@ -34,7 +31,7 @@ class DrawioTest extends TestCase
|
||||
$this->asEditor();
|
||||
$imageName = 'non-accessible-image.png';
|
||||
|
||||
$this->uploadImage($imageName, $page->id);
|
||||
$this->files->uploadGalleryImage($this, $imageName, $page->id);
|
||||
/** @var Image $image */
|
||||
$image = Image::query()->first();
|
||||
$image->type = 'drawio';
|
||||
@ -70,7 +67,7 @@ class DrawioTest extends TestCase
|
||||
$image = Image::where('type', '=', 'drawio')->first();
|
||||
$this->assertTrue(file_exists(public_path($image->path)), 'Uploaded image not found at path: ' . public_path($image->path));
|
||||
|
||||
$testImageData = file_get_contents($this->getTestImageFilePath());
|
||||
$testImageData = $this->files->pngImageData();
|
||||
$uploadedImageData = file_get_contents(public_path($image->path));
|
||||
$this->assertTrue($testImageData === $uploadedImageData, 'Uploaded image file data does not match our test image as expected');
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace Tests\Uploads;
|
||||
|
||||
use BookStack\Entities\Models\Page;
|
||||
use BookStack\Entities\Repos\PageRepo;
|
||||
use BookStack\Uploads\Image;
|
||||
use BookStack\Uploads\ImageService;
|
||||
@ -11,20 +10,18 @@ use Tests\TestCase;
|
||||
|
||||
class ImageTest extends TestCase
|
||||
{
|
||||
use UsesImages;
|
||||
|
||||
public function test_image_upload()
|
||||
{
|
||||
$page = $this->entities->page();
|
||||
$admin = $this->users->admin();
|
||||
$this->actingAs($admin);
|
||||
|
||||
$imgDetails = $this->uploadGalleryImage($page);
|
||||
$imgDetails = $this->files->uploadGalleryImageToPage($this, $page);
|
||||
$relPath = $imgDetails['path'];
|
||||
|
||||
$this->assertTrue(file_exists(public_path($relPath)), 'Uploaded image found at path: ' . public_path($relPath));
|
||||
|
||||
$this->deleteImage($relPath);
|
||||
$this->files->deleteAtRelativePath($relPath);
|
||||
|
||||
$this->assertDatabaseHas('images', [
|
||||
'url' => $this->baseUrl . $relPath,
|
||||
@ -43,9 +40,9 @@ class ImageTest extends TestCase
|
||||
$admin = $this->users->admin();
|
||||
$this->actingAs($admin);
|
||||
|
||||
$originalFile = $this->getTestImageFilePath('compressed.png');
|
||||
$originalFile = $this->files->testFilePath('compressed.png');
|
||||
$originalFileSize = filesize($originalFile);
|
||||
$imgDetails = $this->uploadGalleryImage($page, 'compressed.png');
|
||||
$imgDetails = $this->files->uploadGalleryImageToPage($this, $page, 'compressed.png');
|
||||
$relPath = $imgDetails['path'];
|
||||
|
||||
$this->assertTrue(file_exists(public_path($relPath)), 'Uploaded image found at path: ' . public_path($relPath));
|
||||
@ -55,8 +52,8 @@ class ImageTest extends TestCase
|
||||
$displayImagePath = public_path($displayImageRelPath);
|
||||
$displayFileSize = filesize($displayImagePath);
|
||||
|
||||
$this->deleteImage($relPath);
|
||||
$this->deleteImage($displayImageRelPath);
|
||||
$this->files->deleteAtRelativePath($relPath);
|
||||
$this->files->deleteAtRelativePath($displayImageRelPath);
|
||||
|
||||
$this->assertEquals($originalFileSize, $displayFileSize, 'Display thumbnail generation should not increase image size');
|
||||
}
|
||||
@ -67,8 +64,8 @@ class ImageTest extends TestCase
|
||||
$admin = $this->users->admin();
|
||||
$this->actingAs($admin);
|
||||
|
||||
$imgDetails = $this->uploadGalleryImage($page, 'animated.png');
|
||||
$this->deleteImage($imgDetails['path']);
|
||||
$imgDetails = $this->files->uploadGalleryImageToPage($this, $page, 'animated.png');
|
||||
$this->files->deleteAtRelativePath($imgDetails['path']);
|
||||
|
||||
$this->assertStringContainsString('thumbs-', $imgDetails['response']->thumbs->gallery);
|
||||
$this->assertStringNotContainsString('thumbs-', $imgDetails['response']->thumbs->display);
|
||||
@ -79,7 +76,7 @@ class ImageTest extends TestCase
|
||||
$editor = $this->users->editor();
|
||||
$this->actingAs($editor);
|
||||
|
||||
$imgDetails = $this->uploadGalleryImage();
|
||||
$imgDetails = $this->files->uploadGalleryImageToPage($this, $this->entities->page());
|
||||
$image = Image::query()->first();
|
||||
|
||||
$newName = Str::random();
|
||||
@ -87,7 +84,7 @@ class ImageTest extends TestCase
|
||||
$update->assertSuccessful();
|
||||
$update->assertSee($newName);
|
||||
|
||||
$this->deleteImage($imgDetails['path']);
|
||||
$this->files->deleteAtRelativePath($imgDetails['path']);
|
||||
|
||||
$this->assertDatabaseHas('images', [
|
||||
'type' => 'gallery',
|
||||
@ -99,7 +96,7 @@ class ImageTest extends TestCase
|
||||
{
|
||||
$this->asEditor();
|
||||
|
||||
$imgDetails = $this->uploadGalleryImage();
|
||||
$imgDetails = $this->files->uploadGalleryImageToPage($this, $this->entities->page());
|
||||
$image = Image::query()->first();
|
||||
|
||||
$pageId = $imgDetails['page']->id;
|
||||
@ -129,7 +126,7 @@ class ImageTest extends TestCase
|
||||
$editor = $this->users->editor();
|
||||
$this->actingAs($editor);
|
||||
|
||||
$imgDetails = $this->uploadGalleryImage($page);
|
||||
$imgDetails = $this->files->uploadGalleryImageToPage($this, $page);
|
||||
|
||||
$image = Image::query()->first();
|
||||
$page->html = '<img src="' . $image->url . '">';
|
||||
@ -140,7 +137,7 @@ class ImageTest extends TestCase
|
||||
$usage->assertSeeText($page->name);
|
||||
$usage->assertSee($page->getUrl());
|
||||
|
||||
$this->deleteImage($imgDetails['path']);
|
||||
$this->files->deleteAtRelativePath($imgDetails['path']);
|
||||
}
|
||||
|
||||
public function test_php_files_cannot_be_uploaded()
|
||||
@ -150,10 +147,10 @@ class ImageTest extends TestCase
|
||||
$this->actingAs($admin);
|
||||
|
||||
$fileName = 'bad.php';
|
||||
$relPath = $this->getTestImagePath('gallery', $fileName);
|
||||
$this->deleteImage($relPath);
|
||||
$relPath = $this->files->expectedImagePath('gallery', $fileName);
|
||||
$this->files->deleteAtRelativePath($relPath);
|
||||
|
||||
$file = $this->newTestImageFromBase64('bad-php.base64', $fileName);
|
||||
$file = $this->files->imageFromBase64File('bad-php.base64', $fileName);
|
||||
$upload = $this->withHeader('Content-Type', 'image/jpeg')->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $file], []);
|
||||
$upload->assertStatus(302);
|
||||
|
||||
@ -172,10 +169,10 @@ class ImageTest extends TestCase
|
||||
$this->actingAs($admin);
|
||||
|
||||
$fileName = 'bad.phtml';
|
||||
$relPath = $this->getTestImagePath('gallery', $fileName);
|
||||
$this->deleteImage($relPath);
|
||||
$relPath = $this->files->expectedImagePath('gallery', $fileName);
|
||||
$this->files->deleteAtRelativePath($relPath);
|
||||
|
||||
$file = $this->newTestImageFromBase64('bad-phtml.base64', $fileName);
|
||||
$file = $this->files->imageFromBase64File('bad-phtml.base64', $fileName);
|
||||
$upload = $this->withHeader('Content-Type', 'image/jpeg')->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $file], []);
|
||||
$upload->assertStatus(302);
|
||||
|
||||
@ -189,11 +186,11 @@ class ImageTest extends TestCase
|
||||
$this->actingAs($admin);
|
||||
|
||||
$fileName = 'bad.phtml.png';
|
||||
$relPath = $this->getTestImagePath('gallery', $fileName);
|
||||
$relPath = $this->files->expectedImagePath('gallery', $fileName);
|
||||
$expectedRelPath = dirname($relPath) . '/bad-phtml.png';
|
||||
$this->deleteImage($expectedRelPath);
|
||||
$this->files->deleteAtRelativePath($expectedRelPath);
|
||||
|
||||
$file = $this->newTestImageFromBase64('bad-phtml-png.base64', $fileName);
|
||||
$file = $this->files->imageFromBase64File('bad-phtml-png.base64', $fileName);
|
||||
$upload = $this->withHeader('Content-Type', 'image/png')->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $file], []);
|
||||
$upload->assertStatus(200);
|
||||
|
||||
@ -204,7 +201,7 @@ class ImageTest extends TestCase
|
||||
$this->assertFileDoesNotExist(public_path($relPath), 'Uploaded image file name was not stripped of dots');
|
||||
$this->assertFileExists(public_path($expectedRelPath));
|
||||
|
||||
$this->deleteImage($lastImage->path);
|
||||
$this->files->deleteAtRelativePath($lastImage->path);
|
||||
}
|
||||
|
||||
public function test_url_entities_removed_from_filenames()
|
||||
@ -218,10 +215,10 @@ class ImageTest extends TestCase
|
||||
'#.png',
|
||||
];
|
||||
foreach ($badNames as $name) {
|
||||
$galleryFile = $this->getTestImage($name);
|
||||
$galleryFile = $this->files->uploadedImage($name);
|
||||
$page = $this->entities->page();
|
||||
$badPath = $this->getTestImagePath('gallery', $name);
|
||||
$this->deleteImage($badPath);
|
||||
$badPath = $this->files->expectedImagePath('gallery', $name);
|
||||
$this->files->deleteAtRelativePath($badPath);
|
||||
|
||||
$upload = $this->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $galleryFile], []);
|
||||
$upload->assertStatus(200);
|
||||
@ -235,7 +232,7 @@ class ImageTest extends TestCase
|
||||
|
||||
$this->assertTrue(strlen($newFileName) > 0, 'File name was reduced to nothing');
|
||||
|
||||
$this->deleteImage($lastImage->path);
|
||||
$this->files->deleteAtRelativePath($lastImage->path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,7 +240,7 @@ class ImageTest extends TestCase
|
||||
{
|
||||
config()->set('filesystems.images', 'local_secure');
|
||||
$this->asEditor();
|
||||
$galleryFile = $this->getTestImage('my-secure-test-upload.png');
|
||||
$galleryFile = $this->files->uploadedImage('my-secure-test-upload.png');
|
||||
$page = $this->entities->page();
|
||||
$expectedPath = storage_path('uploads/images/gallery/' . date('Y-m') . '/my-secure-test-upload.png');
|
||||
|
||||
@ -291,7 +288,7 @@ class ImageTest extends TestCase
|
||||
{
|
||||
config()->set('filesystems.images', 'local_secure');
|
||||
$this->asEditor();
|
||||
$galleryFile = $this->getTestImage('my-secure-test-upload.png');
|
||||
$galleryFile = $this->files->uploadedImage('my-secure-test-upload.png');
|
||||
$page = $this->entities->page();
|
||||
$expectedPath = storage_path('uploads/images/gallery/' . date('Y-m') . '/my-secure-test-upload.png');
|
||||
|
||||
@ -314,7 +311,7 @@ class ImageTest extends TestCase
|
||||
{
|
||||
config()->set('filesystems.images', 'local_secure');
|
||||
$this->asAdmin();
|
||||
$galleryFile = $this->getTestImage('my-system-test-upload.png');
|
||||
$galleryFile = $this->files->uploadedImage('my-system-test-upload.png');
|
||||
$expectedPath = public_path('uploads/images/system/' . date('Y-m') . '/my-system-test-upload.png');
|
||||
|
||||
$upload = $this->call('POST', '/settings/customization', [], [], ['app_logo' => $galleryFile], []);
|
||||
@ -331,7 +328,7 @@ class ImageTest extends TestCase
|
||||
{
|
||||
config()->set('filesystems.images', 'local_secure_restricted');
|
||||
$this->asAdmin();
|
||||
$galleryFile = $this->getTestImage('my-system-test-restricted-upload.png');
|
||||
$galleryFile = $this->files->uploadedImage('my-system-test-restricted-upload.png');
|
||||
$expectedPath = public_path('uploads/images/system/' . date('Y-m') . '/my-system-test-restricted-upload.png');
|
||||
|
||||
$upload = $this->call('POST', '/settings/customization', [], [], ['app_logo' => $galleryFile], []);
|
||||
@ -348,7 +345,7 @@ class ImageTest extends TestCase
|
||||
{
|
||||
config()->set('filesystems.images', 'local_secure_restricted');
|
||||
$this->asEditor();
|
||||
$galleryFile = $this->getTestImage('my-secure-restricted-test-upload.png');
|
||||
$galleryFile = $this->files->uploadedImage('my-secure-restricted-test-upload.png');
|
||||
$page = $this->entities->page();
|
||||
|
||||
$upload = $this->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $galleryFile], []);
|
||||
@ -372,7 +369,7 @@ class ImageTest extends TestCase
|
||||
{
|
||||
config()->set('filesystems.images', 'local_secure_restricted');
|
||||
$this->asEditor();
|
||||
$galleryFile = $this->getTestImage('my-secure-restricted-thumb-test-test.png');
|
||||
$galleryFile = $this->files->uploadedImage('my-secure-restricted-thumb-test-test.png');
|
||||
$page = $this->entities->page();
|
||||
|
||||
$upload = $this->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $galleryFile], []);
|
||||
@ -396,12 +393,10 @@ class ImageTest extends TestCase
|
||||
{
|
||||
config()->set('filesystems.images', 'local_secure_restricted');
|
||||
$this->asEditor();
|
||||
$galleryFile = $this->getTestImage('my-secure-restricted-export-test.png');
|
||||
$galleryFile = $this->files->uploadedImage('my-secure-restricted-export-test.png');
|
||||
|
||||
/** @var Page $pageA */
|
||||
/** @var Page $pageB */
|
||||
$pageA = Page::query()->first();
|
||||
$pageB = Page::query()->where('id', '!=', $pageA->id)->first();
|
||||
$pageA = $this->entities->page();
|
||||
$pageB = $this->entities->page();
|
||||
$expectedPath = storage_path('uploads/images/gallery/' . date('Y-m') . '/my-secure-restricted-export-test.png');
|
||||
|
||||
$upload = $this->asEditor()->call('POST', '/images/gallery', ['uploaded_to' => $pageA->id], [], ['file' => $galleryFile], []);
|
||||
@ -430,10 +425,10 @@ class ImageTest extends TestCase
|
||||
$page = $this->entities->page();
|
||||
$this->asAdmin();
|
||||
$imageName = 'first-image.png';
|
||||
$relPath = $this->getTestImagePath('gallery', $imageName);
|
||||
$this->deleteImage($relPath);
|
||||
$relPath = $this->files->expectedImagePath('gallery', $imageName);
|
||||
$this->files->deleteAtRelativePath($relPath);
|
||||
|
||||
$this->uploadImage($imageName, $page->id);
|
||||
$this->files->uploadGalleryImage($this, $imageName, $page->id);
|
||||
$image = Image::first();
|
||||
|
||||
$delete = $this->delete('/images/' . $image->id);
|
||||
@ -453,12 +448,12 @@ class ImageTest extends TestCase
|
||||
$this->asAdmin();
|
||||
$imageName = 'first-image.png';
|
||||
|
||||
$relPath = $this->getTestImagePath('gallery', $imageName);
|
||||
$this->deleteImage($relPath);
|
||||
$relPath = $this->files->expectedImagePath('gallery', $imageName);
|
||||
$this->files->deleteAtRelativePath($relPath);
|
||||
|
||||
$this->uploadImage($imageName, $page->id);
|
||||
$this->uploadImage($imageName, $page->id);
|
||||
$this->uploadImage($imageName, $page->id);
|
||||
$this->files->uploadGalleryImage($this, $imageName, $page->id);
|
||||
$this->files->uploadGalleryImage($this, $imageName, $page->id);
|
||||
$this->files->uploadGalleryImage($this, $imageName, $page->id);
|
||||
|
||||
$image = Image::first();
|
||||
$folder = public_path(dirname($relPath));
|
||||
@ -477,11 +472,11 @@ class ImageTest extends TestCase
|
||||
$page = $this->entities->page();
|
||||
$this->asAdmin();
|
||||
$imageName = 'first-image.png';
|
||||
$relPath = $this->getTestImagePath('gallery', $imageName);
|
||||
$this->deleteImage($relPath);
|
||||
$relPath = $this->files->expectedImagePath('gallery', $imageName);
|
||||
$this->files->deleteAtRelativePath($relPath);
|
||||
$viewer = $this->users->viewer();
|
||||
|
||||
$this->uploadImage($imageName, $page->id);
|
||||
$this->files->uploadGalleryImage($this, $imageName, $page->id);
|
||||
$image = Image::first();
|
||||
|
||||
$resp = $this->get("/images/edit/{$image->id}");
|
||||
@ -495,16 +490,16 @@ class ImageTest extends TestCase
|
||||
$resp = $this->actingAs($viewer)->get("/images/edit/{$image->id}");
|
||||
$this->withHtml($resp)->assertElementExists('button#image-manager-delete[title="Delete"]');
|
||||
|
||||
$this->deleteImage($relPath);
|
||||
$this->files->deleteAtRelativePath($relPath);
|
||||
}
|
||||
|
||||
protected function getTestProfileImage()
|
||||
{
|
||||
$imageName = 'profile.png';
|
||||
$relPath = $this->getTestImagePath('user', $imageName);
|
||||
$this->deleteImage($relPath);
|
||||
$relPath = $this->files->expectedImagePath('user', $imageName);
|
||||
$this->files->deleteAtRelativePath($relPath);
|
||||
|
||||
return $this->getTestImage($imageName);
|
||||
return $this->files->uploadedImage($imageName);
|
||||
}
|
||||
|
||||
public function test_user_image_upload()
|
||||
@ -559,10 +554,10 @@ class ImageTest extends TestCase
|
||||
$this->actingAs($admin);
|
||||
|
||||
$imageName = 'unused-image.png';
|
||||
$relPath = $this->getTestImagePath('gallery', $imageName);
|
||||
$this->deleteImage($relPath);
|
||||
$relPath = $this->files->expectedImagePath('gallery', $imageName);
|
||||
$this->files->deleteAtRelativePath($relPath);
|
||||
|
||||
$upload = $this->uploadImage($imageName, $page->id);
|
||||
$upload = $this->files->uploadGalleryImage($this, $imageName, $page->id);
|
||||
$upload->assertStatus(200);
|
||||
$image = Image::where('type', '=', 'gallery')->first();
|
||||
|
||||
@ -604,6 +599,6 @@ class ImageTest extends TestCase
|
||||
$this->assertCount(1, $toDelete);
|
||||
$this->assertFalse(file_exists($absPath));
|
||||
|
||||
$this->deleteImage($relPath);
|
||||
$this->files->deleteAtRelativePath($relPath);
|
||||
}
|
||||
}
|
||||
|
@ -1,122 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Uploads;
|
||||
|
||||
use BookStack\Entities\Models\Page;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use stdClass;
|
||||
|
||||
trait UsesImages
|
||||
{
|
||||
/**
|
||||
* Get the path to a file in the test-data-directory.
|
||||
*/
|
||||
protected function getTestImageFilePath(?string $fileName = null): string
|
||||
{
|
||||
if (is_null($fileName)) {
|
||||
$fileName = 'test-image.png';
|
||||
}
|
||||
|
||||
return base_path('tests/test-data/' . $fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new temporary image file using the given name,
|
||||
* with the content decoded from the given bas64 file name.
|
||||
* Is generally used for testing sketchy files that could trip AV.
|
||||
*/
|
||||
protected function newTestImageFromBase64(string $base64FileName, $imageFileName): UploadedFile
|
||||
{
|
||||
$imagePath = implode(DIRECTORY_SEPARATOR, [sys_get_temp_dir(), $imageFileName]);
|
||||
$base64FilePath = $this->getTestImageFilePath($base64FileName);
|
||||
$data = file_get_contents($base64FilePath);
|
||||
$decoded = base64_decode($data);
|
||||
file_put_contents($imagePath, $decoded);
|
||||
|
||||
return new UploadedFile($imagePath, $imageFileName, 'image/png', null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a test image that can be uploaded.
|
||||
*/
|
||||
protected function getTestImage(string $fileName, ?string $testDataFileName = null): UploadedFile
|
||||
{
|
||||
return new UploadedFile($this->getTestImageFilePath($testDataFileName), $fileName, 'image/png', null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw file data for the test image.
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
protected function getTestImageContent()
|
||||
{
|
||||
return file_get_contents($this->getTestImageFilePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path for a test image.
|
||||
*/
|
||||
protected function getTestImagePath(string $type, string $fileName): string
|
||||
{
|
||||
return '/uploads/images/' . $type . '/' . date('Y-m') . '/' . $fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads an image with the given name.
|
||||
*
|
||||
* @param $name
|
||||
* @param int $uploadedTo
|
||||
* @param string $contentType
|
||||
*
|
||||
* @return \Illuminate\Foundation\Testing\TestResponse
|
||||
*/
|
||||
protected function uploadImage($name, $uploadedTo = 0, $contentType = 'image/png', ?string $testDataFileName = null)
|
||||
{
|
||||
$file = $this->getTestImage($name, $testDataFileName);
|
||||
|
||||
return $this->withHeader('Content-Type', $contentType)
|
||||
->call('POST', '/images/gallery', ['uploaded_to' => $uploadedTo], [], ['file' => $file], []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a new gallery image.
|
||||
* Returns the image name.
|
||||
* Can provide a page to relate the image to.
|
||||
*
|
||||
* @param Page|null $page
|
||||
*
|
||||
* @return array{name: string, path: string, page: Page, response: stdClass}
|
||||
*/
|
||||
protected function uploadGalleryImage(Page $page = null, ?string $testDataFileName = null)
|
||||
{
|
||||
if ($page === null) {
|
||||
$page = $this->entities->page();
|
||||
}
|
||||
|
||||
$imageName = $testDataFileName ?? 'first-image.png';
|
||||
$relPath = $this->getTestImagePath('gallery', $imageName);
|
||||
$this->deleteImage($relPath);
|
||||
|
||||
$upload = $this->uploadImage($imageName, $page->id, 'image/png', $testDataFileName);
|
||||
$upload->assertStatus(200);
|
||||
|
||||
return [
|
||||
'name' => $imageName,
|
||||
'path' => $relPath,
|
||||
'page' => $page,
|
||||
'response' => json_decode($upload->getContent()),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an uploaded image.
|
||||
*/
|
||||
protected function deleteImage(string $relPath)
|
||||
{
|
||||
$path = public_path($relPath);
|
||||
if (file_exists($path)) {
|
||||
unlink($path);
|
||||
}
|
||||
}
|
||||
}
|
@ -12,12 +12,9 @@ use Illuminate\Support\Str;
|
||||
use Mockery\MockInterface;
|
||||
use RuntimeException;
|
||||
use Tests\TestCase;
|
||||
use Tests\Uploads\UsesImages;
|
||||
|
||||
class UserManagementTest extends TestCase
|
||||
{
|
||||
use UsesImages;
|
||||
|
||||
public function test_user_creation()
|
||||
{
|
||||
/** @var User $user */
|
||||
@ -282,7 +279,7 @@ class UserManagementTest extends TestCase
|
||||
public function test_user_avatar_update_and_reset()
|
||||
{
|
||||
$user = $this->users->viewer();
|
||||
$avatarFile = $this->getTestImage('avatar-icon.png');
|
||||
$avatarFile = $this->files->uploadedImage('avatar-icon.png');
|
||||
|
||||
$this->assertEquals(0, $user->image_id);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user