]> BookStack Code Mirror - bookstack/blob - tests/Api/PagesApiTest.php
Merge branch 'markdown-export' of https://github.com/nikhiljha/BookStack-1 into nikhi...
[bookstack] / tests / Api / PagesApiTest.php
1 <?php namespace Tests\Api;
2
3 use BookStack\Entities\Models\Book;
4 use BookStack\Entities\Models\Chapter;
5 use BookStack\Entities\Models\Page;
6 use Tests\TestCase;
7
8 class PagesApiTest extends TestCase
9 {
10     use TestsApi;
11
12     protected $baseEndpoint = '/api/pages';
13
14     public function test_index_endpoint_returns_expected_page()
15     {
16         $this->actingAsApiEditor();
17         $firstPage = Page::query()->orderBy('id', 'asc')->first();
18
19         $resp = $this->getJson($this->baseEndpoint . '?count=1&sort=+id');
20         $resp->assertJson(['data' => [
21             [
22                 'id' => $firstPage->id,
23                 'name' => $firstPage->name,
24                 'slug' => $firstPage->slug,
25                 'book_id' => $firstPage->book->id,
26                 'priority' => $firstPage->priority,
27             ]
28         ]]);
29     }
30
31     public function test_create_endpoint()
32     {
33         $this->actingAsApiEditor();
34         $book = Book::query()->first();
35         $details = [
36             'name' => 'My API page',
37             'book_id' => $book->id,
38             'html' => '<p>My new page content</p>',
39             'tags' => [
40                 [
41                     'name' => 'tagname',
42                     'value' => 'tagvalue',
43                 ]
44             ]
45         ];
46
47         $resp = $this->postJson($this->baseEndpoint, $details);
48         unset($details['html']);
49         $resp->assertStatus(200);
50         $newItem = Page::query()->orderByDesc('id')->where('name', '=', $details['name'])->first();
51         $resp->assertJson(array_merge($details, ['id' => $newItem->id, 'slug' => $newItem->slug]));
52         $this->assertDatabaseHas('tags', [
53             'entity_id' => $newItem->id,
54             'entity_type' => $newItem->getMorphClass(),
55             'name' => 'tagname',
56             'value' => 'tagvalue',
57         ]);
58         $resp->assertSeeText('My new page content');
59         $resp->assertJsonMissing(['book' => []]);
60         $this->assertActivityExists('page_create', $newItem);
61     }
62
63     public function test_page_name_needed_to_create()
64     {
65         $this->actingAsApiEditor();
66         $book = Book::query()->first();
67         $details = [
68             'book_id' => $book->id,
69             'html' => '<p>A page created via the API</p>',
70         ];
71
72         $resp = $this->postJson($this->baseEndpoint, $details);
73         $resp->assertStatus(422);
74         $resp->assertJson($this->validationResponse([
75             "name" => ["The name field is required."]
76         ]));
77     }
78
79     public function test_book_id_or_chapter_id_needed_to_create()
80     {
81         $this->actingAsApiEditor();
82         $details = [
83             'name' => 'My api page',
84             'html' => '<p>A page created via the API</p>',
85         ];
86
87         $resp = $this->postJson($this->baseEndpoint, $details);
88         $resp->assertStatus(422);
89         $resp->assertJson($this->validationResponse([
90             "book_id" => ["The book id field is required when chapter id is not present."],
91             "chapter_id" => ["The chapter id field is required when book id is not present."]
92         ]));
93
94         $chapter = Chapter::visible()->first();
95         $resp = $this->postJson($this->baseEndpoint, array_merge($details, ['chapter_id' => $chapter->id]));
96         $resp->assertStatus(200);
97
98         $book = Book::visible()->first();
99         $resp = $this->postJson($this->baseEndpoint, array_merge($details, ['book_id' => $book->id]));
100         $resp->assertStatus(200);
101     }
102
103     public function test_markdown_can_be_provided_for_create()
104     {
105         $this->actingAsApiEditor();
106         $book = Book::visible()->first();
107         $details = [
108             'book_id' => $book->id,
109             'name' => 'My api page',
110             'markdown' => "# A new API page \n[link](https://example.com)",
111         ];
112
113         $resp = $this->postJson($this->baseEndpoint, $details);
114         $resp->assertJson(['markdown' => $details['markdown']]);
115
116         $respHtml = $resp->json('html');
117         $this->assertStringContainsString('new API page</h1>', $respHtml);
118         $this->assertStringContainsString('link</a>', $respHtml);
119         $this->assertStringContainsString('href="https://example.com"', $respHtml);
120     }
121
122     public function test_read_endpoint()
123     {
124         $this->actingAsApiEditor();
125         $page = Page::visible()->first();
126
127         $resp = $this->getJson($this->baseEndpoint . "/{$page->id}");
128         $resp->assertStatus(200);
129         $resp->assertJson([
130             'id' => $page->id,
131             'slug' => $page->slug,
132             'created_by' => [
133                 'name' => $page->createdBy->name,
134             ],
135             'book_id' => $page->book_id,
136             'updated_by' => [
137                 'name' => $page->createdBy->name,
138             ],
139             'owned_by' => [
140                 'name' => $page->ownedBy->name
141             ],
142         ]);
143     }
144
145     public function test_read_endpoint_provides_rendered_html()
146     {
147         $this->actingAsApiEditor();
148         $page = Page::visible()->first();
149         $page->html = "<p>testing</p><script>alert('danger')</script><h1>Hello</h1>";
150         $page->save();
151
152         $resp = $this->getJson($this->baseEndpoint . "/{$page->id}");
153         $html = $resp->json('html');
154         $this->assertStringNotContainsString('script', $html);
155         $this->assertStringContainsString('Hello', $html);
156         $this->assertStringContainsString('testing', $html);
157     }
158
159     public function test_update_endpoint()
160     {
161         $this->actingAsApiEditor();
162         $page = Page::visible()->first();
163         $details = [
164             'name' => 'My updated API page',
165             'html' => '<p>A page created via the API</p>',
166             'tags' => [
167                 [
168                     'name' => 'freshtag',
169                     'value' => 'freshtagval',
170                 ]
171             ],
172         ];
173
174         $resp = $this->putJson($this->baseEndpoint . "/{$page->id}", $details);
175         $page->refresh();
176
177         $resp->assertStatus(200);
178         unset($details['html']);
179         $resp->assertJson(array_merge($details, [
180             'id' => $page->id, 'slug' => $page->slug, 'book_id' => $page->book_id
181         ]));
182         $this->assertActivityExists('page_update', $page);
183     }
184
185     public function test_providing_new_chapter_id_on_update_will_move_page()
186     {
187         $this->actingAsApiEditor();
188         $page = Page::visible()->first();
189         $chapter = Chapter::visible()->where('book_id', '!=', $page->book_id)->first();
190         $details = [
191             'name' => 'My updated API page',
192             'chapter_id' => $chapter->id,
193             'html' => '<p>A page created via the API</p>',
194         ];
195
196         $resp = $this->putJson($this->baseEndpoint . "/{$page->id}", $details);
197         $resp->assertStatus(200);
198         $resp->assertJson([
199             'chapter_id' => $chapter->id,
200             'book_id' => $chapter->book_id,
201         ]);
202     }
203
204     public function test_providing_move_via_update_requires_page_create_permission_on_new_parent()
205     {
206         $this->actingAsApiEditor();
207         $page = Page::visible()->first();
208         $chapter = Chapter::visible()->where('book_id', '!=', $page->book_id)->first();
209         $this->setEntityRestrictions($chapter, ['view'], [$this->getEditor()->roles()->first()]);
210         $details = [
211             'name' => 'My updated API page',
212             'chapter_id' => $chapter->id,
213             'html' => '<p>A page created via the API</p>',
214         ];
215
216         $resp = $this->putJson($this->baseEndpoint . "/{$page->id}", $details);
217         $resp->assertStatus(403);
218     }
219
220     public function test_delete_endpoint()
221     {
222         $this->actingAsApiEditor();
223         $page = Page::visible()->first();
224         $resp = $this->deleteJson($this->baseEndpoint . "/{$page->id}");
225
226         $resp->assertStatus(204);
227         $this->assertActivityExists('page_delete', $page);
228     }
229
230     public function test_export_html_endpoint()
231     {
232         $this->actingAsApiEditor();
233         $page = Page::visible()->first();
234
235         $resp = $this->get($this->baseEndpoint . "/{$page->id}/export/html");
236         $resp->assertStatus(200);
237         $resp->assertSee($page->name);
238         $resp->assertHeader('Content-Disposition', 'attachment; filename="' . $page->slug . '.html"');
239     }
240
241     public function test_export_plain_text_endpoint()
242     {
243         $this->actingAsApiEditor();
244         $page = Page::visible()->first();
245
246         $resp = $this->get($this->baseEndpoint . "/{$page->id}/export/plaintext");
247         $resp->assertStatus(200);
248         $resp->assertSee($page->name);
249         $resp->assertHeader('Content-Disposition', 'attachment; filename="' . $page->slug . '.txt"');
250     }
251
252     public function test_export_pdf_endpoint()
253     {
254         $this->actingAsApiEditor();
255         $page = Page::visible()->first();
256
257         $resp = $this->get($this->baseEndpoint . "/{$page->id}/export/pdf");
258         $resp->assertStatus(200);
259         $resp->assertHeader('Content-Disposition', 'attachment; filename="' . $page->slug . '.pdf"');
260     }
261 }