From 37ea8054f28bd7726ac9c4ddea9587758f7a8e6f Mon Sep 17 00:00:00 2001 From: Spitfire Date: Thu, 12 Oct 2023 15:44:10 -0600 Subject: [PATCH] API: Manage Thumbnails --- .../Api/v1/DefaultThumbnailApiController.php | 69 +++++++++++++++++ .../Campaigns/DestroyDefaultThumbnail.php | 31 ++++++++ .../Campaigns/StoreDefaultThumbnail.php | 33 ++++++++ app/Models/Campaign.php | 13 ++++ resources/api-docs/1.0/default-images.md | 75 +++++++++++++++++++ resources/api-docs/1.0/index.md | 1 + routes/api.v1.php | 4 + .../Entities/EntityDefaultThumbnailTest.php | 30 ++++++++ tests/TestCase.php | 8 ++ 9 files changed, 264 insertions(+) create mode 100644 app/Http/Controllers/Api/v1/DefaultThumbnailApiController.php create mode 100644 app/Http/Requests/Campaigns/DestroyDefaultThumbnail.php create mode 100644 app/Http/Requests/Campaigns/StoreDefaultThumbnail.php create mode 100644 resources/api-docs/1.0/default-images.md create mode 100644 tests/Feature/Entities/EntityDefaultThumbnailTest.php diff --git a/app/Http/Controllers/Api/v1/DefaultThumbnailApiController.php b/app/Http/Controllers/Api/v1/DefaultThumbnailApiController.php new file mode 100644 index 0000000000..1643eec92e --- /dev/null +++ b/app/Http/Controllers/Api/v1/DefaultThumbnailApiController.php @@ -0,0 +1,69 @@ +authorize('access', $campaign); + + return response()->json($campaign->getDefaultImages()); + } + + /** + * @return Resource + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function upload(StoreDefaultThumbnail $request, Campaign $campaign) + { + $this->authorize('access', $campaign); + + if ($campaign->premium()){ + /** @var DefaultImageService $service */ + $service = app()->make(DefaultImageService::class); + $type = Str::plural(array_search($request->post('entity_type'), config('entities.ids'))); + + if ($service->campaign($campaign)->type($type)->save($request)) { + return response()->json([ + 'data' => 'Default thumbnail succesfully uploaded' + ]); + } + } + return response()->json(['error' => 'Invalid input'], 422); + } + + /** + * @param Request $request + * @return \Illuminate\Http\JsonResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function delete(DestroyDefaultThumbnail $request, Campaign $campaign) { + if ($campaign->premium()){ + /** @var DefaultImageService $service */ + $service = app()->make(DefaultImageService::class); + $this->authorize('recover', $campaign); + $type = Str::plural(array_search($request->post('entity_type'), config('entities.ids'))); + + $result = $service->campaign($campaign)->type($type)->destroy(); + + if ($result) { + return response()->json([ + 'data' => 'Default thumbnail succesfully deleted' + ]); + } + } + return response()->json(['error' => 'Invalid input'], 422); + } +} diff --git a/app/Http/Requests/Campaigns/DestroyDefaultThumbnail.php b/app/Http/Requests/Campaigns/DestroyDefaultThumbnail.php new file mode 100644 index 0000000000..b847b03f60 --- /dev/null +++ b/app/Http/Requests/Campaigns/DestroyDefaultThumbnail.php @@ -0,0 +1,31 @@ + 'required|exists:entity_types,id', + ]; + return $rules; + } +} diff --git a/app/Http/Requests/Campaigns/StoreDefaultThumbnail.php b/app/Http/Requests/Campaigns/StoreDefaultThumbnail.php new file mode 100644 index 0000000000..dff2000872 --- /dev/null +++ b/app/Http/Requests/Campaigns/StoreDefaultThumbnail.php @@ -0,0 +1,33 @@ + 'required|exists:entity_types,id', + 'default_entity_image' => 'required|mimes:jpeg,png,jpg,gif,webp|max:' . Limit::upload(), + ]; + return $rules; + } +} diff --git a/app/Models/Campaign.php b/app/Models/Campaign.php index a047a35ebc..cd08efdb14 100644 --- a/app/Models/Campaign.php +++ b/app/Models/Campaign.php @@ -382,6 +382,19 @@ public function defaultImages(): array return $data; } + /** + * Prepare the default entity images + */ + public function getDefaultImages(): array + { + $data = []; + foreach($this->defaultImages() as $image) { + $data[] = ['entity_type' => $image['type'], 'url' => Img::url($image['path'])]; + } + + return $data; + } + /** * Determine if a campaign has plugins of the theme type */ diff --git a/resources/api-docs/1.0/default-images.md b/resources/api-docs/1.0/default-images.md new file mode 100644 index 0000000000..10f6388643 --- /dev/null +++ b/resources/api-docs/1.0/default-images.md @@ -0,0 +1,75 @@ +# Images + +--- + +- [All Default Images](#all-images) +- [Create a Image](#create-image) +- [Delete a Image](#delete-image) + + +## All Images + +You can get a list of all the default images of a campaign by using the following endpoint. This is a superboosted campaign feature! If the campaign isn't superboosted, this API endpoint will result in a 404. + +> {warning} Don't forget that all endpoints documented here need to be prefixed with `{{version}}/campaigns/{campaign.id}/`. + + +| Method | URI | Headers | +| :- | :- | :- | +| GET/HEAD | `default-thumbnails` | Default | + +### Results +```json +{ + "data": [ + { + "entity_type": "abilities", + "url": "https://th.kanka.io/gR8y1nxfEhBC1nVYdQpr2pUW3lY=/48x48/smart/src/app/logos/logo.png", + }, + { + "entity_type": "creatures", + "url": "https://th.kanka.io/gR8y1nxfEhBC1nVYdQpr2pUW3lY=/48x48/smart/src/app/logos/logo.png", + } + ] +} +``` + + +## Create a Default Image + +To create a default image, use the following endpoint. + +| Method | URI | Headers | +| :- | :- | :- | +| POST | `default-thumbnails` | Default | + +### Body + +| Parameter | Type | Detail | +|:------------| :- | :- | +| `entity_type` | `integer`(required) | The entity type id | +| `default_entity_image` | `file` | File uploaded | + + +### Results + +> {success} Code 200 with JSON. + + +## Delete a Default Image + +To delete a default image, use the following endpoint. + +| Method | URI | Headers | +| :- | :- | :- | +| DELETE | `default-thumbnails` | Default | + +### Body + +| Parameter | Type | Detail | +|:------------| :- | :- | +| `entity_type` | `integer`(required) | The entity type id | + +### Results + +> {success} Code 200 with JSON. diff --git a/resources/api-docs/1.0/index.md b/resources/api-docs/1.0/index.md index 9bc354e036..3546a5c9b9 100644 --- a/resources/api-docs/1.0/index.md +++ b/resources/api-docs/1.0/index.md @@ -56,6 +56,7 @@ - [Pagination](/api-docs/{{version}}/pagination) - [Bookmarks](/api-docs/{{version}}/bookmark) - [Dashboard Widgets](/api-docs/{{version}}/dashboard-widgets) + - [Default Images](/api-docs/{{version}}/default-images) - [Mention Language](/api-docs/{{version}}/mention-language) - [Gallery](/api-docs/{{version}}/images) - [Templates](/api-docs/{{version}}/templates) diff --git a/routes/api.v1.php b/routes/api.v1.php index 7f6a091280..3dff8e54d2 100644 --- a/routes/api.v1.php +++ b/routes/api.v1.php @@ -104,6 +104,10 @@ Route::post('campaigns/{campaign}/transfer', [\App\Http\Controllers\Api\v1\EntityMoveApiController::class, 'transfer']); +Route::get('campaigns/{campaign}/default-thumbnails', [\App\Http\Controllers\Api\v1\DefaultThumbnailApiController::class, 'index']); +Route::post('campaigns/{campaign}/default-thumbnails', [\App\Http\Controllers\Api\v1\DefaultThumbnailApiController::class, 'upload']); +Route::delete('campaigns/{campaign}/default-thumbnails', [\App\Http\Controllers\Api\v1\DefaultThumbnailApiController::class, 'delete']); + Route::get('profile', [\App\Http\Controllers\Api\v1\ProfileApiController::class, 'index']); Route::get('version', function () { return config('app.version'); diff --git a/tests/Feature/Entities/EntityDefaultThumbnailTest.php b/tests/Feature/Entities/EntityDefaultThumbnailTest.php new file mode 100644 index 0000000000..07cc47a8cb --- /dev/null +++ b/tests/Feature/Entities/EntityDefaultThumbnailTest.php @@ -0,0 +1,30 @@ +asUser(true) + ->withCampaign(['boost_count' => 4]) + ->postJson('/api/1.0/campaigns/1/default-thumbnails', [ + 'entity_type' => 2, + 'default_entity_image' => UploadedFile::fake()->image('avatar.jpg') + ]) + ->assertJsonFragment(["data" => "Default thumbnail succesfully uploaded"]) +; + +it('GETS all default thumbnails') + ->asUser(true) + ->withCampaign(['boost_count' => 4, 'default_images' => ["characters" => "1"]]) + ->withImages() + ->get('/api/1.0/campaigns/1/default-thumbnails') + ->assertStatus(200) +; + +it('DELETES a default thumbnail') + ->asUser(true) + ->withCampaign(['boost_count' => 4, 'default_images' => ["characters" => "1"]]) + ->withImages() + ->delete('/api/1.0/campaigns/1/default-thumbnails', ['entity_type' => 1 ]) + ->assertJsonFragment(["data" => "Default thumbnail succesfully deleted"]) + +; diff --git a/tests/TestCase.php b/tests/TestCase.php index a49dd6c860..3b947edc94 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -472,6 +472,14 @@ public function withImages(array $extra = []): self return $this; } + public function withThumbnails(array $extra = []): self + { + Image::factory() + ->count(1) + ->create(['campaign_id' => 1] + $extra); + return $this; + } + public function withCharacterTags(array $extra = []): self { Character::factory()