5 use BookStack\Entities\Models\Book;
6 use BookStack\Entities\Models\Bookshelf;
7 use BookStack\Entities\Repos\BaseRepo;
9 use Illuminate\Support\Facades\DB;
12 class ShelvesApiTest extends TestCase
16 protected string $baseEndpoint = '/api/shelves';
18 public function test_index_endpoint_returns_expected_shelf()
20 $this->actingAsApiEditor();
21 $firstBookshelf = Bookshelf::query()->orderBy('id', 'asc')->first();
23 $resp = $this->getJson($this->baseEndpoint . '?count=1&sort=+id');
24 $resp->assertJson(['data' => [
26 'id' => $firstBookshelf->id,
27 'name' => $firstBookshelf->name,
28 'slug' => $firstBookshelf->slug,
29 'owned_by' => $firstBookshelf->owned_by,
30 'created_by' => $firstBookshelf->created_by,
31 'updated_by' => $firstBookshelf->updated_by,
37 public function test_index_endpoint_includes_cover_if_set()
39 $this->actingAsApiEditor();
40 $shelf = $this->entities->shelf();
42 $baseRepo = $this->app->make(BaseRepo::class);
43 $image = $this->files->uploadedImage('shelf_cover');
44 $baseRepo->updateCoverImage($shelf, $image);
46 $resp = $this->getJson($this->baseEndpoint . '?filter[id]=' . $shelf->id);
47 $resp->assertJson(['data' => [
51 'id' => $shelf->cover->id,
52 'url' => $shelf->cover->url,
58 public function test_create_endpoint()
60 $this->actingAsApiEditor();
61 $books = Book::query()->take(2)->get();
64 'name' => 'My API shelf',
65 'description' => 'A shelf created via the API',
68 $resp = $this->postJson($this->baseEndpoint, array_merge($details, ['books' => [$books[0]->id, $books[1]->id]]));
69 $resp->assertStatus(200);
70 $newItem = Bookshelf::query()->orderByDesc('id')->where('name', '=', $details['name'])->first();
71 $resp->assertJson(array_merge($details, [
73 'slug' => $newItem->slug,
74 'description_html' => '<p>A shelf created via the API</p>',
76 $this->assertActivityExists('bookshelf_create', $newItem);
77 foreach ($books as $index => $book) {
78 $this->assertDatabaseHas('bookshelves_books', [
79 'bookshelf_id' => $newItem->id,
80 'book_id' => $book->id,
86 public function test_create_endpoint_with_html()
88 $this->actingAsApiEditor();
91 'name' => 'My API shelf',
92 'description_html' => '<p>A <strong>shelf</strong> created via the API</p>',
95 $resp = $this->postJson($this->baseEndpoint, $details);
96 $resp->assertStatus(200);
97 $newItem = Bookshelf::query()->orderByDesc('id')->where('name', '=', $details['name'])->first();
99 $expectedDetails = array_merge($details, [
100 'id' => $newItem->id,
101 'description' => 'A shelf created via the API',
104 $resp->assertJson($expectedDetails);
105 $this->assertDatabaseHas('bookshelves', $expectedDetails);
108 public function test_shelf_name_needed_to_create()
110 $this->actingAsApiEditor();
112 'description' => 'A shelf created via the API',
115 $resp = $this->postJson($this->baseEndpoint, $details);
116 $resp->assertStatus(422);
119 'message' => 'The given data was invalid.',
121 'name' => ['The name field is required.'],
128 public function test_read_endpoint()
130 $this->actingAsApiEditor();
131 $shelf = Bookshelf::visible()->first();
133 $resp = $this->getJson($this->baseEndpoint . "/{$shelf->id}");
135 $resp->assertStatus(200);
138 'slug' => $shelf->slug,
140 'name' => $shelf->createdBy->name,
143 'name' => $shelf->createdBy->name,
146 'name' => $shelf->ownedBy->name,
151 public function test_update_endpoint()
153 $this->actingAsApiEditor();
154 $shelf = Bookshelf::visible()->first();
156 'name' => 'My updated API shelf',
157 'description' => 'A shelf updated via the API',
160 $resp = $this->putJson($this->baseEndpoint . "/{$shelf->id}", $details);
163 $resp->assertStatus(200);
164 $resp->assertJson(array_merge($details, [
166 'slug' => $shelf->slug,
167 'description_html' => '<p>A shelf updated via the API</p>',
169 $this->assertActivityExists('bookshelf_update', $shelf);
172 public function test_update_endpoint_with_html()
174 $this->actingAsApiEditor();
175 $shelf = Bookshelf::visible()->first();
177 'name' => 'My updated API shelf',
178 'description_html' => '<p>A shelf <em>updated</em> via the API</p>',
181 $resp = $this->putJson($this->baseEndpoint . "/{$shelf->id}", $details);
182 $resp->assertStatus(200);
184 $this->assertDatabaseHas('bookshelves', array_merge($details, ['id' => $shelf->id, 'description' => 'A shelf updated via the API']));
187 public function test_update_increments_updated_date_if_only_tags_are_sent()
189 $this->actingAsApiEditor();
190 $shelf = Bookshelf::visible()->first();
191 DB::table('bookshelves')->where('id', '=', $shelf->id)->update(['updated_at' => Carbon::now()->subWeek()]);
194 'tags' => [['name' => 'Category', 'value' => 'Testing']],
197 $this->putJson($this->baseEndpoint . "/{$shelf->id}", $details);
199 $this->assertGreaterThan(Carbon::now()->subDay()->unix(), $shelf->updated_at->unix());
202 public function test_update_only_assigns_books_if_param_provided()
204 $this->actingAsApiEditor();
205 $shelf = Bookshelf::visible()->first();
206 $this->assertTrue($shelf->books()->count() > 0);
208 'name' => 'My updated API shelf',
211 $resp = $this->putJson($this->baseEndpoint . "/{$shelf->id}", $details);
212 $resp->assertStatus(200);
213 $this->assertTrue($shelf->books()->count() > 0);
215 $resp = $this->putJson($this->baseEndpoint . "/{$shelf->id}", ['books' => []]);
216 $resp->assertStatus(200);
217 $this->assertTrue($shelf->books()->count() === 0);
220 public function test_update_cover_image_control()
222 $this->actingAsApiEditor();
223 /** @var Book $shelf */
224 $shelf = Bookshelf::visible()->first();
225 $this->assertNull($shelf->cover);
226 $file = $this->files->uploadedImage('image.png');
228 // Ensure cover image can be set via API
229 $resp = $this->call('PUT', $this->baseEndpoint . "/{$shelf->id}", [
230 'name' => 'My updated API shelf with image',
231 ], [], ['image' => $file]);
234 $resp->assertStatus(200);
235 $this->assertNotNull($shelf->cover);
237 // Ensure further updates without image do not clear cover image
238 $resp = $this->put($this->baseEndpoint . "/{$shelf->id}", [
239 'name' => 'My updated shelf again',
243 $resp->assertStatus(200);
244 $this->assertNotNull($shelf->cover);
246 // Ensure update with null image property clears image
247 $resp = $this->put($this->baseEndpoint . "/{$shelf->id}", [
252 $resp->assertStatus(200);
253 $this->assertNull($shelf->cover);
256 public function test_delete_endpoint()
258 $this->actingAsApiEditor();
259 $shelf = Bookshelf::visible()->first();
260 $resp = $this->deleteJson($this->baseEndpoint . "/{$shelf->id}");
262 $resp->assertStatus(204);
263 $this->assertActivityExists('bookshelf_delete');