3 use BookStack\Uploads\Attachment;
4 use BookStack\Entities\Page;
5 use BookStack\Auth\Permissions\PermissionService;
7 class AttachmentTest extends TestCase
10 * Get a test file that can be uploaded
12 * @return \Illuminate\Http\UploadedFile
14 protected function getTestFile($fileName)
16 return new \Illuminate\Http\UploadedFile(base_path('tests/test-data/test-file.txt'), $fileName, 'text/plain', 55, null, true);
20 * Uploads a file with the given name.
22 * @param int $uploadedTo
23 * @return \Illuminate\Foundation\Testing\TestResponse
25 protected function uploadFile($name, $uploadedTo = 0)
27 $file = $this->getTestFile($name);
28 return $this->call('POST', '/attachments/upload', ['uploaded_to' => $uploadedTo], [], ['file' => $file], []);
32 * Delete all uploaded files.
33 * To assist with cleanup.
35 protected function deleteUploads()
37 $fileService = $this->app->make(\BookStack\Uploads\AttachmentService::class);
38 foreach (\BookStack\Uploads\Attachment::all() as $file) {
39 $fileService->deleteFile($file);
43 public function test_file_upload()
45 $page = Page::first();
47 $admin = $this->getAdmin();
48 $fileName = 'upload_test_file.txt';
52 'uploaded_to'=> $page->id,
55 'created_by' => $admin->id,
56 'updated_by' => $admin->id,
59 $upload = $this->uploadFile($fileName, $page->id);
60 $upload->assertStatus(200);
62 $attachment = Attachment::query()->orderBy('id', 'desc')->first();
63 $expectedResp['path'] = $attachment->path;
65 $upload->assertJson($expectedResp);
66 $this->assertDatabaseHas('attachments', $expectedResp);
68 $this->deleteUploads();
71 public function test_file_upload_does_not_use_filename()
73 $page = Page::first();
74 $fileName = 'upload_test_file.txt';
77 $upload = $this->asAdmin()->uploadFile($fileName, $page->id);
78 $upload->assertStatus(200);
80 $attachment = Attachment::query()->orderBy('id', 'desc')->first();
81 $this->assertStringNotContainsString($fileName, $attachment->path);
82 $this->assertStringEndsWith('.txt', $attachment->path);
85 public function test_file_display_and_access()
87 $page = Page::first();
89 $fileName = 'upload_test_file.txt';
91 $upload = $this->uploadFile($fileName, $page->id);
92 $upload->assertStatus(200);
93 $attachment = Attachment::orderBy('id', 'desc')->take(1)->first();
95 $pageGet = $this->get($page->getUrl());
96 $pageGet->assertSeeText($fileName);
97 $pageGet->assertSee($attachment->getUrl());
99 $attachmentGet = $this->get($attachment->getUrl());
100 $attachmentGet->assertSee('Hi, This is a test file for testing the upload process.');
102 $this->deleteUploads();
105 public function test_attaching_link_to_page()
107 $page = Page::first();
108 $admin = $this->getAdmin();
111 $linkReq = $this->call('POST', 'attachments/link', [
112 'link' => 'https://example.com',
113 'name' => 'Example Attachment Link',
114 'uploaded_to' => $page->id,
118 'path' => 'https://example.com',
119 'name' => 'Example Attachment Link',
120 'uploaded_to' => $page->id,
121 'created_by' => $admin->id,
122 'updated_by' => $admin->id,
128 $linkReq->assertStatus(200);
129 $linkReq->assertJson($expectedResp);
130 $this->assertDatabaseHas('attachments', $expectedResp);
131 $attachment = Attachment::orderBy('id', 'desc')->take(1)->first();
133 $pageGet = $this->get($page->getUrl());
134 $pageGet->assertSeeText('Example Attachment Link');
135 $pageGet->assertSee($attachment->getUrl());
137 $attachmentGet = $this->get($attachment->getUrl());
138 $attachmentGet->assertRedirect('https://example.com');
140 $this->deleteUploads();
143 public function test_attachment_updating()
145 $page = Page::first();
148 $this->call('POST', 'attachments/link', [
149 'link' => 'https://example.com',
150 'name' => 'Example Attachment Link',
151 'uploaded_to' => $page->id,
154 $attachmentId = \BookStack\Uploads\Attachment::first()->id;
156 $update = $this->call('PUT', 'attachments/' . $attachmentId, [
157 'uploaded_to' => $page->id,
158 'name' => 'My new attachment name',
159 'link' => 'https://test.example.com'
163 'path' => 'https://test.example.com',
164 'name' => 'My new attachment name',
165 'uploaded_to' => $page->id
168 $update->assertStatus(200);
169 $update->assertJson($expectedResp);
170 $this->assertDatabaseHas('attachments', $expectedResp);
172 $this->deleteUploads();
175 public function test_file_deletion()
177 $page = Page::first();
179 $fileName = 'deletion_test.txt';
180 $this->uploadFile($fileName, $page->id);
182 $attachment = Attachment::query()->orderBy('id', 'desc')->first();
183 $filePath = storage_path($attachment->path);
184 $this->assertTrue(file_exists($filePath), 'File at path ' . $filePath . ' does not exist');
186 $attachment = \BookStack\Uploads\Attachment::first();
187 $this->delete($attachment->getUrl());
189 $this->assertDatabaseMissing('attachments', [
192 $this->assertFalse(file_exists($filePath), 'File at path ' . $filePath . ' was not deleted as expected');
194 $this->deleteUploads();
197 public function test_attachment_deletion_on_page_deletion()
199 $page = Page::first();
201 $fileName = 'deletion_test.txt';
202 $this->uploadFile($fileName, $page->id);
204 $attachment = Attachment::query()->orderBy('id', 'desc')->first();
205 $filePath = storage_path($attachment->path);
207 $this->assertTrue(file_exists($filePath), 'File at path ' . $filePath . ' does not exist');
208 $this->assertDatabaseHas('attachments', [
212 $this->call('DELETE', $page->getUrl());
214 $this->assertDatabaseMissing('attachments', [
217 $this->assertFalse(file_exists($filePath), 'File at path ' . $filePath . ' was not deleted as expected');
219 $this->deleteUploads();
222 public function test_attachment_access_without_permission_shows_404()
224 $admin = $this->getAdmin();
225 $viewer = $this->getViewer();
226 $page = Page::first(); /** @var Page $page */
228 $this->actingAs($admin);
229 $fileName = 'permission_test.txt';
230 $this->uploadFile($fileName, $page->id);
231 $attachment = Attachment::orderBy('id', 'desc')->take(1)->first();
233 $page->restricted = true;
234 $page->permissions()->delete();
236 $page->rebuildPermissions();
237 $page->load('jointPermissions');
239 $this->actingAs($viewer);
240 $attachmentGet = $this->get($attachment->getUrl());
241 $attachmentGet->assertStatus(404);
242 $attachmentGet->assertSee("Attachment not found");
244 $this->deleteUploads();