1 <?php namespace Tests\Uploads;
3 use BookStack\Entities\Managers\TrashCan;
4 use BookStack\Entities\Repos\PageRepo;
5 use BookStack\Uploads\Attachment;
6 use BookStack\Entities\Page;
7 use BookStack\Auth\Permissions\PermissionService;
10 class AttachmentTest extends TestCase
13 * Get a test file that can be uploaded
15 * @return \Illuminate\Http\UploadedFile
17 protected function getTestFile($fileName)
19 return new \Illuminate\Http\UploadedFile(base_path('tests/test-data/test-file.txt'), $fileName, 'text/plain', 55, null, true);
23 * Uploads a file with the given name.
25 * @param int $uploadedTo
26 * @return \Illuminate\Foundation\Testing\TestResponse
28 protected function uploadFile($name, $uploadedTo = 0)
30 $file = $this->getTestFile($name);
31 return $this->call('POST', '/attachments/upload', ['uploaded_to' => $uploadedTo], [], ['file' => $file], []);
35 * Delete all uploaded files.
36 * To assist with cleanup.
38 protected function deleteUploads()
40 $fileService = $this->app->make(\BookStack\Uploads\AttachmentService::class);
41 foreach (Attachment::all() as $file) {
42 $fileService->deleteFile($file);
46 public function test_file_upload()
48 $page = Page::first();
50 $admin = $this->getAdmin();
51 $fileName = 'upload_test_file.txt';
55 'uploaded_to'=> $page->id,
58 'created_by' => $admin->id,
59 'updated_by' => $admin->id,
62 $upload = $this->uploadFile($fileName, $page->id);
63 $upload->assertStatus(200);
65 $attachment = Attachment::query()->orderBy('id', 'desc')->first();
66 $expectedResp['path'] = $attachment->path;
68 $upload->assertJson($expectedResp);
69 $this->assertDatabaseHas('attachments', $expectedResp);
71 $this->deleteUploads();
74 public function test_file_upload_does_not_use_filename()
76 $page = Page::first();
77 $fileName = 'upload_test_file.txt';
80 $upload = $this->asAdmin()->uploadFile($fileName, $page->id);
81 $upload->assertStatus(200);
83 $attachment = Attachment::query()->orderBy('id', 'desc')->first();
84 $this->assertStringNotContainsString($fileName, $attachment->path);
85 $this->assertStringEndsWith('.txt', $attachment->path);
88 public function test_file_display_and_access()
90 $page = Page::first();
92 $fileName = 'upload_test_file.txt';
94 $upload = $this->uploadFile($fileName, $page->id);
95 $upload->assertStatus(200);
96 $attachment = Attachment::orderBy('id', 'desc')->take(1)->first();
98 $pageGet = $this->get($page->getUrl());
99 $pageGet->assertSeeText($fileName);
100 $pageGet->assertSee($attachment->getUrl());
102 $attachmentGet = $this->get($attachment->getUrl());
103 $attachmentGet->assertSee('Hi, This is a test file for testing the upload process.');
105 $this->deleteUploads();
108 public function test_attaching_link_to_page()
110 $page = Page::first();
111 $admin = $this->getAdmin();
114 $linkReq = $this->call('POST', 'attachments/link', [
115 'attachment_link_url' => 'https://example.com',
116 'attachment_link_name' => 'Example Attachment Link',
117 'attachment_link_uploaded_to' => $page->id,
121 'path' => 'https://example.com',
122 'name' => 'Example Attachment Link',
123 'uploaded_to' => $page->id,
124 'created_by' => $admin->id,
125 'updated_by' => $admin->id,
131 $linkReq->assertStatus(200);
132 $this->assertDatabaseHas('attachments', $expectedData);
133 $attachment = Attachment::orderBy('id', 'desc')->take(1)->first();
135 $pageGet = $this->get($page->getUrl());
136 $pageGet->assertSeeText('Example Attachment Link');
137 $pageGet->assertSee($attachment->getUrl());
139 $attachmentGet = $this->get($attachment->getUrl());
140 $attachmentGet->assertRedirect('https://example.com');
142 $this->deleteUploads();
145 public function test_attachment_updating()
147 $page = Page::first();
150 $this->call('POST', 'attachments/link', [
151 'attachment_link_url' => 'https://example.com',
152 'attachment_link_name' => 'Example Attachment Link',
153 'attachment_link_uploaded_to' => $page->id,
156 $attachmentId = Attachment::first()->id;
158 $update = $this->call('PUT', 'attachments/' . $attachmentId, [
159 'attachment_edit_name' => 'My new attachment name',
160 'attachment_edit_url' => 'https://test.example.com'
164 'id' => $attachmentId,
165 'path' => 'https://test.example.com',
166 'name' => 'My new attachment name',
167 'uploaded_to' => $page->id
170 $update->assertStatus(200);
171 $this->assertDatabaseHas('attachments', $expectedData);
173 $this->deleteUploads();
176 public function test_file_deletion()
178 $page = Page::first();
180 $fileName = 'deletion_test.txt';
181 $this->uploadFile($fileName, $page->id);
183 $attachment = Attachment::query()->orderBy('id', 'desc')->first();
184 $filePath = storage_path($attachment->path);
185 $this->assertTrue(file_exists($filePath), 'File at path ' . $filePath . ' does not exist');
187 $attachment = Attachment::first();
188 $this->delete($attachment->getUrl());
190 $this->assertDatabaseMissing('attachments', [
193 $this->assertFalse(file_exists($filePath), 'File at path ' . $filePath . ' was not deleted as expected');
195 $this->deleteUploads();
198 public function test_attachment_deletion_on_page_deletion()
200 $page = Page::first();
202 $fileName = 'deletion_test.txt';
203 $this->uploadFile($fileName, $page->id);
205 $attachment = Attachment::query()->orderBy('id', 'desc')->first();
206 $filePath = storage_path($attachment->path);
208 $this->assertTrue(file_exists($filePath), 'File at path ' . $filePath . ' does not exist');
209 $this->assertDatabaseHas('attachments', [
213 app(PageRepo::class)->destroy($page);
214 app(TrashCan::class)->empty();
216 $this->assertDatabaseMissing('attachments', [
219 $this->assertFalse(file_exists($filePath), 'File at path ' . $filePath . ' was not deleted as expected');
221 $this->deleteUploads();
224 public function test_attachment_access_without_permission_shows_404()
226 $admin = $this->getAdmin();
227 $viewer = $this->getViewer();
228 $page = Page::first(); /** @var Page $page */
230 $this->actingAs($admin);
231 $fileName = 'permission_test.txt';
232 $this->uploadFile($fileName, $page->id);
233 $attachment = Attachment::orderBy('id', 'desc')->take(1)->first();
235 $page->restricted = true;
236 $page->permissions()->delete();
238 $page->rebuildPermissions();
239 $page->load('jointPermissions');
241 $this->actingAs($viewer);
242 $attachmentGet = $this->get($attachment->getUrl());
243 $attachmentGet->assertStatus(404);
244 $attachmentGet->assertSee("Attachment not found");
246 $this->deleteUploads();