mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-07-11 01:24:46 +02:00
feat(api): adding artist resource pivot endpoints (#528)
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Api\Field\Pivot\Wiki\ArtistResource;
|
||||
|
||||
use App\Contracts\Http\Api\Field\CreatableField;
|
||||
use App\Contracts\Http\Api\Field\SelectableField;
|
||||
use App\Http\Api\Field\Field;
|
||||
use App\Http\Api\Query\Query;
|
||||
use App\Http\Api\Schema\Schema;
|
||||
use App\Models\Wiki\Artist;
|
||||
use App\Pivots\Wiki\ArtistResource;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
/**
|
||||
* Class ArtistResourceArtistIdField.
|
||||
*/
|
||||
class ArtistResourceArtistIdField extends Field implements CreatableField, SelectableField
|
||||
{
|
||||
/**
|
||||
* Create a new field instance.
|
||||
*
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function __construct(Schema $schema)
|
||||
{
|
||||
parent::__construct($schema, ArtistResource::ATTRIBUTE_ARTIST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the creation validation rules for the field.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function getCreationRules(Request $request): array
|
||||
{
|
||||
return [
|
||||
'required',
|
||||
'integer',
|
||||
Rule::exists(Artist::TABLE, Artist::ATTRIBUTE_ID),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the field should be included in the select clause of our query.
|
||||
*
|
||||
* @param Query $query
|
||||
* @param Schema $schema
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldSelect(Query $query, Schema $schema): bool
|
||||
{
|
||||
// Needed to match artist relation.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Api\Field\Pivot\Wiki\ArtistResource;
|
||||
|
||||
use App\Contracts\Http\Api\Field\CreatableField;
|
||||
use App\Contracts\Http\Api\Field\UpdatableField;
|
||||
use App\Http\Api\Field\StringField;
|
||||
use App\Http\Api\Schema\Schema;
|
||||
use App\Pivots\Wiki\ArtistResource;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Class ArtistResourceAsField.
|
||||
*/
|
||||
class ArtistResourceAsField extends StringField implements CreatableField, UpdatableField
|
||||
{
|
||||
/**
|
||||
* Create a new field instance.
|
||||
*
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function __construct(Schema $schema)
|
||||
{
|
||||
parent::__construct($schema, ArtistResource::ATTRIBUTE_AS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the creation validation rules for the field.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function getCreationRules(Request $request): array
|
||||
{
|
||||
return [
|
||||
'nullable',
|
||||
'string',
|
||||
'max:192',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the update validation rules for the field.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function getUpdateRules(Request $request): array
|
||||
{
|
||||
return [
|
||||
'nullable',
|
||||
'string',
|
||||
'max:192',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Api\Field\Pivot\Wiki\ArtistResource;
|
||||
|
||||
use App\Contracts\Http\Api\Field\CreatableField;
|
||||
use App\Contracts\Http\Api\Field\SelectableField;
|
||||
use App\Http\Api\Field\Field;
|
||||
use App\Http\Api\Query\Query;
|
||||
use App\Http\Api\Schema\Schema;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Pivots\Wiki\ArtistResource;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
/**
|
||||
* Class ArtistResourceResourceIdField.
|
||||
*/
|
||||
class ArtistResourceResourceIdField extends Field implements CreatableField, SelectableField
|
||||
{
|
||||
/**
|
||||
* Create a new field instance.
|
||||
*
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function __construct(Schema $schema)
|
||||
{
|
||||
parent::__construct($schema, ArtistResource::ATTRIBUTE_RESOURCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the creation validation rules for the field.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function getCreationRules(Request $request): array
|
||||
{
|
||||
return [
|
||||
'required',
|
||||
'integer',
|
||||
Rule::exists(ExternalResource::TABLE, ExternalResource::ATTRIBUTE_ID),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the field should be included in the select clause of our query.
|
||||
*
|
||||
* @param Query $query
|
||||
* @param Schema $schema
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldSelect(Query $query, Schema $schema): bool
|
||||
{
|
||||
// Needed to match resource relation.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Api\Schema\Pivot\Wiki;
|
||||
|
||||
use App\Http\Api\Field\Base\CreatedAtField;
|
||||
use App\Http\Api\Field\Base\UpdatedAtField;
|
||||
use App\Http\Api\Field\Field;
|
||||
use App\Http\Api\Field\Pivot\Wiki\ArtistResource\ArtistResourceArtistIdField;
|
||||
use App\Http\Api\Field\Pivot\Wiki\ArtistResource\ArtistResourceAsField;
|
||||
use App\Http\Api\Field\Pivot\Wiki\ArtistResource\ArtistResourceResourceIdField;
|
||||
use App\Http\Api\Include\AllowedInclude;
|
||||
use App\Http\Api\Schema\EloquentSchema;
|
||||
use App\Http\Api\Schema\Wiki\ArtistSchema;
|
||||
use App\Http\Api\Schema\Wiki\ExternalResourceSchema;
|
||||
use App\Http\Resources\Pivot\Wiki\Resource\ArtistResourceResource;
|
||||
use App\Pivots\Wiki\ArtistResource;
|
||||
|
||||
/**
|
||||
* Class ArtistResourceSchema.
|
||||
*/
|
||||
class ArtistResourceSchema extends EloquentSchema
|
||||
{
|
||||
/**
|
||||
* The model this schema represents.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function model(): string
|
||||
{
|
||||
return ArtistResource::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of the resource.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function type(): string
|
||||
{
|
||||
return ArtistResourceResource::$wrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the allowed includes.
|
||||
*
|
||||
* @return AllowedInclude[]
|
||||
*/
|
||||
public function allowedIncludes(): array
|
||||
{
|
||||
return [
|
||||
new AllowedInclude(new ArtistSchema(), ArtistResource::RELATION_ARTIST),
|
||||
new AllowedInclude(new ExternalResourceSchema(), ArtistResource::RELATION_RESOURCE),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the direct fields of the resource.
|
||||
*
|
||||
* @return Field[]
|
||||
*
|
||||
* @noinspection PhpMissingParentCallCommonInspection
|
||||
*/
|
||||
public function fields(): array
|
||||
{
|
||||
return [
|
||||
new CreatedAtField($this),
|
||||
new UpdatedAtField($this),
|
||||
new ArtistResourceArtistIdField($this),
|
||||
new ArtistResourceResourceIdField($this),
|
||||
new ArtistResourceAsField($this),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Api\Pivot\Wiki;
|
||||
|
||||
use App\Actions\Http\Api\DestroyAction;
|
||||
use App\Actions\Http\Api\IndexAction;
|
||||
use App\Actions\Http\Api\ShowAction;
|
||||
use App\Actions\Http\Api\StoreAction;
|
||||
use App\Actions\Http\Api\UpdateAction;
|
||||
use App\Http\Api\Query\Query;
|
||||
use App\Http\Controllers\Api\Pivot\PivotController;
|
||||
use App\Http\Requests\Api\IndexRequest;
|
||||
use App\Http\Requests\Api\ShowRequest;
|
||||
use App\Http\Requests\Api\StoreRequest;
|
||||
use App\Http\Requests\Api\UpdateRequest;
|
||||
use App\Http\Resources\Pivot\Wiki\Collection\ArtistResourceCollection;
|
||||
use App\Http\Resources\Pivot\Wiki\Resource\ArtistResourceResource;
|
||||
use App\Models\Wiki\Artist;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Pivots\Wiki\ArtistResource;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class ArtistResourceController.
|
||||
*/
|
||||
class ArtistResourceController extends PivotController
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(Artist::class, 'artist', ExternalResource::class, 'resource');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param IndexRequest $request
|
||||
* @param IndexAction $action
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function index(IndexRequest $request, IndexAction $action): JsonResponse
|
||||
{
|
||||
$query = new Query($request->validated());
|
||||
|
||||
$resources = $action->index(ArtistResource::query(), $query, $request->schema());
|
||||
|
||||
$collection = new ArtistResourceCollection($resources, $query);
|
||||
|
||||
return $collection->toResponse($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource.
|
||||
*
|
||||
* @param StoreRequest $request
|
||||
* @param StoreAction $action
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function store(StoreRequest $request, StoreAction $action): JsonResponse
|
||||
{
|
||||
$artistResource = $action->store(ArtistResource::query(), $request->validated());
|
||||
|
||||
$resource = new ArtistResourceResource($artistResource, new Query());
|
||||
|
||||
return $resource->toResponse($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param ShowRequest $request
|
||||
* @param Artist $artist
|
||||
* @param ExternalResource $resource
|
||||
* @param ShowAction $action
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function show(ShowRequest $request, Artist $artist, ExternalResource $resource, ShowAction $action): JsonResponse
|
||||
{
|
||||
$artistResource = ArtistResource::query()
|
||||
->where(ArtistResource::ATTRIBUTE_ARTIST, $artist->getKey())
|
||||
->where(ArtistResource::ATTRIBUTE_RESOURCE, $resource->getKey())
|
||||
->firstOrFail();
|
||||
|
||||
$query = new Query($request->validated());
|
||||
|
||||
$show = $action->show($artistResource, $query, $request->schema());
|
||||
|
||||
$apiResource = new ArtistResourceResource($show, $query);
|
||||
|
||||
return $apiResource->toResponse($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource.
|
||||
*
|
||||
* @param UpdateRequest $request
|
||||
* @param Artist $artist
|
||||
* @param ExternalResource $resource
|
||||
* @param UpdateAction $action
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function update(UpdateRequest $request, Artist $artist, ExternalResource $resource, UpdateAction $action): JsonResponse
|
||||
{
|
||||
$artistResource = ArtistResource::query()
|
||||
->where(ArtistResource::ATTRIBUTE_ARTIST, $artist->getKey())
|
||||
->where(ArtistResource::ATTRIBUTE_RESOURCE, $resource->getKey())
|
||||
->firstOrFail();
|
||||
|
||||
$query = new Query($request->validated());
|
||||
|
||||
$updated = $action->update($artistResource, $request->validated());
|
||||
|
||||
$apiResource = new ArtistResourceResource($updated, $query);
|
||||
|
||||
return $apiResource->toResponse($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource.
|
||||
*
|
||||
* @param Artist $artist
|
||||
* @param ExternalResource $resource
|
||||
* @param DestroyAction $action
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function destroy(Artist $artist, ExternalResource $resource, DestroyAction $action): JsonResponse
|
||||
{
|
||||
$artistResource = ArtistResource::query()
|
||||
->where(ArtistResource::ATTRIBUTE_ARTIST, $artist->getKey())
|
||||
->where(ArtistResource::ATTRIBUTE_RESOURCE, $resource->getKey())
|
||||
->firstOrFail();
|
||||
|
||||
$action->destroy($artistResource);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => "Resource '**{$resource->getName()}**' has been detached from Artist '**{$artist->getName()}**'.",
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Resources\Pivot\Wiki\Collection;
|
||||
|
||||
use App\Http\Resources\BaseCollection;
|
||||
use App\Http\Resources\Pivot\Wiki\Resource\ArtistResourceResource;
|
||||
use App\Pivots\Wiki\ArtistResource;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Class ArtistResourceCollection.
|
||||
*/
|
||||
class ArtistResourceCollection extends BaseCollection
|
||||
{
|
||||
/**
|
||||
* The "data" wrapper that should be applied.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public static $wrap = 'artistresources';
|
||||
|
||||
/**
|
||||
* Transform the resource into a JSON array.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*
|
||||
* @noinspection PhpMissingParentCallCommonInspection
|
||||
*/
|
||||
public function toArray($request): array
|
||||
{
|
||||
return $this->collection->map(fn (ArtistResource $artistResource) => new ArtistResourceResource($artistResource, $this->query))->all();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Resources\Pivot\Wiki\Resource;
|
||||
|
||||
use App\Http\Api\Schema\Pivot\Wiki\ArtistResourceSchema;
|
||||
use App\Http\Api\Schema\Schema;
|
||||
use App\Http\Resources\BaseResource;
|
||||
use App\Http\Resources\Wiki\Resource\ArtistResource;
|
||||
use App\Http\Resources\Wiki\Resource\ExternalResourceResource;
|
||||
use App\Pivots\Wiki\ArtistResource as ArtistResourcePivot;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Class ArtistResourceResource.
|
||||
*/
|
||||
class ArtistResourceResource extends BaseResource
|
||||
{
|
||||
/**
|
||||
* The "data" wrapper that should be applied.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public static $wrap = 'artistresource';
|
||||
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request): array
|
||||
{
|
||||
$result = parent::toArray($request);
|
||||
|
||||
$result[ArtistResourcePivot::RELATION_ARTIST] = new ArtistResource($this->whenLoaded(ArtistResourcePivot::RELATION_ARTIST), $this->query);
|
||||
$result[ArtistResourcePivot::RELATION_RESOURCE] = new ExternalResourceResource($this->whenLoaded(ArtistResourcePivot::RELATION_RESOURCE), $this->query);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the resource schema.
|
||||
*
|
||||
* @return Schema
|
||||
*/
|
||||
protected function schema(): Schema
|
||||
{
|
||||
return new ArtistResourceSchema();
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,10 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
* Class ArtistResource.
|
||||
*
|
||||
* @property Artist $artist
|
||||
* @property int $artist_id
|
||||
* @property string $as
|
||||
* @property ExternalResource $resource
|
||||
* @property int $resource_id
|
||||
*
|
||||
* @method static ArtistResourceFactory factory(...$parameters)
|
||||
*/
|
||||
@@ -30,13 +32,18 @@ class ArtistResource extends BasePivot
|
||||
final public const ATTRIBUTE_ARTIST = 'artist_id';
|
||||
final public const ATTRIBUTE_RESOURCE = 'resource_id';
|
||||
|
||||
final public const RELATION_ARTIST = 'artist';
|
||||
final public const RELATION_RESOURCE = 'resource';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $fillable = [
|
||||
ArtistResource::ATTRIBUTE_ARTIST,
|
||||
ArtistResource::ATTRIBUTE_AS,
|
||||
ArtistResource::ATTRIBUTE_RESOURCE,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,6 +22,7 @@ use App\Http\Controllers\Api\Pivot\Wiki\AnimeSeriesController;
|
||||
use App\Http\Controllers\Api\Pivot\Wiki\AnimeStudioController;
|
||||
use App\Http\Controllers\Api\Pivot\Wiki\AnimeThemeEntryVideoController;
|
||||
use App\Http\Controllers\Api\Pivot\Wiki\ArtistImageController;
|
||||
use App\Http\Controllers\Api\Pivot\Wiki\ArtistResourceController;
|
||||
use App\Http\Controllers\Api\Wiki\Anime\SynonymController;
|
||||
use App\Http\Controllers\Api\Wiki\Anime\Theme\EntryController;
|
||||
use App\Http\Controllers\Api\Wiki\Anime\ThemeController;
|
||||
@@ -244,6 +245,7 @@ apiPivotResource('animeseries', 'anime', 'series', AnimeSeriesController::class)
|
||||
apiPivotResource('animestudio', 'anime', 'studio', AnimeStudioController::class);
|
||||
apiPivotResource('animethemeentryvideo', 'animethemeentry', 'video', AnimeThemeEntryVideoController::class);
|
||||
apiPivotResource('artistimage', 'artist', 'image', ArtistImageController::class);
|
||||
apiEditablePivotResource('artistresource', 'artist', 'resource', ArtistResourceController::class);
|
||||
|
||||
// Wiki Routes
|
||||
apiResource('anime', AnimeController::class);
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Http\Api\Pivot\Wiki\ArtistResource;
|
||||
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\Wiki\Artist;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Pivots\Wiki\ArtistResource;
|
||||
use Illuminate\Foundation\Testing\WithoutEvents;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Class ArtistResourceDestroyTest.
|
||||
*/
|
||||
class ArtistResourceDestroyTest extends TestCase
|
||||
{
|
||||
use WithoutEvents;
|
||||
|
||||
/**
|
||||
* The Artist Resource Destroy Endpoint shall be protected by sanctum.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testProtected(): void
|
||||
{
|
||||
$artistResource = ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->createOne();
|
||||
|
||||
$response = $this->delete(route('api.artistresource.destroy', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource]));
|
||||
|
||||
$response->assertUnauthorized();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Destroy Endpoint shall forbid users without the delete artist & delete resource permissions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testForbidden(): void
|
||||
{
|
||||
$artistResource = ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->createOne();
|
||||
|
||||
$user = User::factory()->createOne();
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->delete(route('api.artistresource.destroy', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource]));
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Destroy Endpoint shall return an error if the artist resource does not exist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotFound(): void
|
||||
{
|
||||
$artist = Artist::factory()->createOne();
|
||||
$resource = ExternalResource::factory()->createOne();
|
||||
|
||||
$user = User::factory()->withPermissions(['delete artist', 'delete external resource'])->createOne();
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->delete(route('api.artistresource.destroy', ['artist' => $artist, 'resource' => $resource]));
|
||||
|
||||
$response->assertNotFound();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Destroy Endpoint shall delete the artist resource.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDeleted(): void
|
||||
{
|
||||
$artistResource = ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->createOne();
|
||||
|
||||
$user = User::factory()->withPermissions(['delete artist', 'delete external resource'])->createOne();
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->delete(route('api.artistresource.destroy', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource]));
|
||||
|
||||
$response->assertOk();
|
||||
static::assertModelMissing($artistResource);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Http\Api\Pivot\Wiki\ArtistResource;
|
||||
|
||||
use App\Concerns\Actions\Http\Api\SortsModels;
|
||||
use App\Contracts\Http\Api\Field\SortableField;
|
||||
use App\Enums\Http\Api\Sort\Direction;
|
||||
use App\Enums\Models\Wiki\ResourceSite;
|
||||
use App\Http\Api\Criteria\Paging\Criteria;
|
||||
use App\Http\Api\Criteria\Paging\OffsetCriteria;
|
||||
use App\Http\Api\Field\Field;
|
||||
use App\Http\Api\Include\AllowedInclude;
|
||||
use App\Http\Api\Parser\FieldParser;
|
||||
use App\Http\Api\Parser\FilterParser;
|
||||
use App\Http\Api\Parser\IncludeParser;
|
||||
use App\Http\Api\Parser\PagingParser;
|
||||
use App\Http\Api\Parser\SortParser;
|
||||
use App\Http\Api\Query\Query;
|
||||
use App\Http\Api\Schema\Pivot\Wiki\ArtistResourceSchema;
|
||||
use App\Http\Resources\Pivot\Wiki\Collection\ArtistResourceCollection;
|
||||
use App\Http\Resources\Pivot\Wiki\Resource\ArtistResourceResource;
|
||||
use App\Models\Wiki\Artist;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Pivots\BasePivot;
|
||||
use App\Pivots\Wiki\ArtistResource;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Illuminate\Foundation\Testing\WithoutEvents;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Class ArtistResourceIndexTest.
|
||||
*/
|
||||
class ArtistResourceIndexTest extends TestCase
|
||||
{
|
||||
use SortsModels;
|
||||
use WithFaker;
|
||||
use WithoutEvents;
|
||||
|
||||
/**
|
||||
* By default, the Artist Resource Index Endpoint shall return a collection of Artist Resource Resources.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDefault(): void
|
||||
{
|
||||
Collection::times($this->faker->randomDigitNotNull(), function () {
|
||||
ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->create();
|
||||
});
|
||||
|
||||
$artistResources = ArtistResource::all();
|
||||
|
||||
$response = $this->get(route('api.artistresource.index'));
|
||||
|
||||
$response->assertJson(
|
||||
json_decode(
|
||||
json_encode(
|
||||
(new ArtistResourceCollection($artistResources, new Query()))
|
||||
->response()
|
||||
->getData()
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Theme Index Endpoint shall be paginated.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPaginated(): void
|
||||
{
|
||||
Collection::times($this->faker->randomDigitNotNull(), function () {
|
||||
ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->create();
|
||||
});
|
||||
|
||||
$response = $this->get(route('api.artistresource.index'));
|
||||
|
||||
$response->assertJsonStructure([
|
||||
ArtistResourceCollection::$wrap,
|
||||
'links',
|
||||
'meta',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Index Endpoint shall allow inclusion of related resources.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAllowedIncludePaths(): void
|
||||
{
|
||||
$schema = new ArtistResourceSchema();
|
||||
|
||||
$allowedIncludes = collect($schema->allowedIncludes());
|
||||
|
||||
$selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count()));
|
||||
|
||||
$includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path());
|
||||
|
||||
$parameters = [
|
||||
IncludeParser::param() => $includedPaths->join(','),
|
||||
];
|
||||
|
||||
Collection::times($this->faker->randomDigitNotNull(), function () {
|
||||
ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->create();
|
||||
});
|
||||
|
||||
$response = $this->get(route('api.artistresource.index', $parameters));
|
||||
|
||||
$artistResources = ArtistResource::with($includedPaths->all())->get();
|
||||
|
||||
$response->assertJson(
|
||||
json_decode(
|
||||
json_encode(
|
||||
(new ArtistResourceCollection($artistResources, new Query($parameters)))
|
||||
->response()
|
||||
->getData()
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Index Endpoint shall implement sparse fieldsets.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSparseFieldsets(): void
|
||||
{
|
||||
$schema = new ArtistResourceSchema();
|
||||
|
||||
$fields = collect($schema->fields());
|
||||
|
||||
$includedFields = $fields->random($this->faker->numberBetween(1, $fields->count()));
|
||||
|
||||
$parameters = [
|
||||
FieldParser::param() => [
|
||||
ArtistResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','),
|
||||
],
|
||||
];
|
||||
|
||||
Collection::times($this->faker->randomDigitNotNull(), function () {
|
||||
ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->create();
|
||||
});
|
||||
|
||||
$response = $this->get(route('api.artistresource.index', $parameters));
|
||||
|
||||
$artistResources = ArtistResource::all();
|
||||
|
||||
$response->assertJson(
|
||||
json_decode(
|
||||
json_encode(
|
||||
(new ArtistResourceCollection($artistResources, new Query($parameters)))
|
||||
->response()
|
||||
->getData()
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Index Endpoint shall support sorting resources.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSorts(): void
|
||||
{
|
||||
$schema = new ArtistResourceSchema();
|
||||
|
||||
$sort = collect($schema->fields())
|
||||
->filter(fn (Field $field) => $field instanceof SortableField)
|
||||
->map(fn (SortableField $field) => $field->getSort())
|
||||
->random();
|
||||
|
||||
$parameters = [
|
||||
SortParser::param() => $sort->format(Direction::getRandomInstance()),
|
||||
];
|
||||
|
||||
$query = new Query($parameters);
|
||||
|
||||
Collection::times($this->faker->randomDigitNotNull(), function () {
|
||||
ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->create();
|
||||
});
|
||||
|
||||
$response = $this->get(route('api.artistresource.index', $parameters));
|
||||
|
||||
$artistResources = $this->sort(ArtistResource::query(), $query, $schema)->get();
|
||||
|
||||
$response->assertJson(
|
||||
json_decode(
|
||||
json_encode(
|
||||
(new ArtistResourceCollection($artistResources, $query))
|
||||
->response()
|
||||
->getData()
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Index Endpoint shall support filtering by created_at.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCreatedAtFilter(): void
|
||||
{
|
||||
$createdFilter = $this->faker->date();
|
||||
$excludedDate = $this->faker->date();
|
||||
|
||||
$parameters = [
|
||||
FilterParser::param() => [
|
||||
BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter,
|
||||
],
|
||||
PagingParser::param() => [
|
||||
OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS,
|
||||
],
|
||||
];
|
||||
|
||||
Carbon::withTestNow($createdFilter, function () {
|
||||
Collection::times($this->faker->randomDigitNotNull(), function () {
|
||||
ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->create();
|
||||
});
|
||||
});
|
||||
|
||||
Carbon::withTestNow($excludedDate, function () {
|
||||
Collection::times($this->faker->randomDigitNotNull(), function () {
|
||||
ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->create();
|
||||
});
|
||||
});
|
||||
|
||||
$artistResources = ArtistResource::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get();
|
||||
|
||||
$response = $this->get(route('api.artistresource.index', $parameters));
|
||||
|
||||
$response->assertJson(
|
||||
json_decode(
|
||||
json_encode(
|
||||
(new ArtistResourceCollection($artistResources, new Query($parameters)))
|
||||
->response()
|
||||
->getData()
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Index Endpoint shall support filtering by updated_at.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testUpdatedAtFilter(): void
|
||||
{
|
||||
$updatedFilter = $this->faker->date();
|
||||
$excludedDate = $this->faker->date();
|
||||
|
||||
$parameters = [
|
||||
FilterParser::param() => [
|
||||
BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter,
|
||||
],
|
||||
PagingParser::param() => [
|
||||
OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS,
|
||||
],
|
||||
];
|
||||
|
||||
Carbon::withTestNow($updatedFilter, function () {
|
||||
Collection::times($this->faker->randomDigitNotNull(), function () {
|
||||
ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->create();
|
||||
});
|
||||
});
|
||||
|
||||
Carbon::withTestNow($excludedDate, function () {
|
||||
Collection::times($this->faker->randomDigitNotNull(), function () {
|
||||
ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->create();
|
||||
});
|
||||
});
|
||||
|
||||
$artistResources = ArtistResource::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get();
|
||||
|
||||
$response = $this->get(route('api.artistresource.index', $parameters));
|
||||
|
||||
$response->assertJson(
|
||||
json_decode(
|
||||
json_encode(
|
||||
(new ArtistResourceCollection($artistResources, new Query($parameters)))
|
||||
->response()
|
||||
->getData()
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Index Endpoint shall support constrained eager loading of resources by site.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResourcesBySite(): void
|
||||
{
|
||||
$siteFilter = ResourceSite::getRandomInstance();
|
||||
|
||||
$parameters = [
|
||||
FilterParser::param() => [
|
||||
ExternalResource::ATTRIBUTE_SITE => $siteFilter->description,
|
||||
],
|
||||
IncludeParser::param() => ArtistResource::RELATION_RESOURCE,
|
||||
];
|
||||
|
||||
Collection::times($this->faker->randomDigitNotNull(), function () {
|
||||
ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->create();
|
||||
});
|
||||
|
||||
$response = $this->get(route('api.artistresource.index', $parameters));
|
||||
|
||||
$artistResources = ArtistResource::with([
|
||||
ArtistResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) {
|
||||
$query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value);
|
||||
},
|
||||
])
|
||||
->get();
|
||||
|
||||
$response->assertJson(
|
||||
json_decode(
|
||||
json_encode(
|
||||
(new ArtistResourceCollection($artistResources, new Query($parameters)))
|
||||
->response()
|
||||
->getData()
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Http\Api\Pivot\Wiki\ArtistResource;
|
||||
|
||||
use App\Enums\Models\Wiki\ResourceSite;
|
||||
use App\Http\Api\Field\Field;
|
||||
use App\Http\Api\Include\AllowedInclude;
|
||||
use App\Http\Api\Parser\FieldParser;
|
||||
use App\Http\Api\Parser\FilterParser;
|
||||
use App\Http\Api\Parser\IncludeParser;
|
||||
use App\Http\Api\Query\Query;
|
||||
use App\Http\Api\Schema\Pivot\Wiki\ArtistResourceSchema;
|
||||
use App\Http\Resources\Pivot\Wiki\Resource\ArtistResourceResource;
|
||||
use App\Models\Wiki\Artist;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Pivots\Wiki\ArtistResource;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Illuminate\Foundation\Testing\WithoutEvents;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Class ArtistResourceShowTest.
|
||||
*/
|
||||
class ArtistResourceShowTest extends TestCase
|
||||
{
|
||||
use WithFaker;
|
||||
use WithoutEvents;
|
||||
|
||||
/**
|
||||
* The Artist Resource Show Endpoint shall return an error if the artist resource does not exist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotFound(): void
|
||||
{
|
||||
$artist = Artist::factory()->createOne();
|
||||
$resource = ExternalResource::factory()->createOne();
|
||||
|
||||
$response = $this->get(route('api.artistresource.show', ['artist' => $artist, 'resource' => $resource]));
|
||||
|
||||
$response->assertNotFound();
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, the Artist Resource Show Endpoint shall return an Artist Resource Resource.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDefault(): void
|
||||
{
|
||||
$artistResource = ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->createOne();
|
||||
|
||||
$response = $this->get(route('api.artistresource.show', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource]));
|
||||
|
||||
$artistResource->unsetRelations();
|
||||
|
||||
$response->assertJson(
|
||||
json_decode(
|
||||
json_encode(
|
||||
(new ArtistResourceResource($artistResource, new Query()))
|
||||
->response()
|
||||
->getData()
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Show Endpoint shall allow inclusion of related resources.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAllowedIncludePaths(): void
|
||||
{
|
||||
$schema = new ArtistResourceSchema();
|
||||
|
||||
$allowedIncludes = collect($schema->allowedIncludes());
|
||||
|
||||
$selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count()));
|
||||
|
||||
$includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path());
|
||||
|
||||
$parameters = [
|
||||
IncludeParser::param() => $includedPaths->join(','),
|
||||
];
|
||||
|
||||
$artistResource = ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->createOne();
|
||||
|
||||
$response = $this->get(route('api.artistresource.show', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters));
|
||||
|
||||
$artistResource->unsetRelations()->load($includedPaths->all());
|
||||
|
||||
$response->assertJson(
|
||||
json_decode(
|
||||
json_encode(
|
||||
(new ArtistResourceResource($artistResource, new Query($parameters)))
|
||||
->response()
|
||||
->getData()
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Show Endpoint shall implement sparse fieldsets.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSparseFieldsets(): void
|
||||
{
|
||||
$schema = new ArtistResourceSchema();
|
||||
|
||||
$fields = collect($schema->fields());
|
||||
|
||||
$includedFields = $fields->random($this->faker->numberBetween(1, $fields->count()));
|
||||
|
||||
$parameters = [
|
||||
FieldParser::param() => [
|
||||
ArtistResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','),
|
||||
],
|
||||
];
|
||||
|
||||
$artistResource = ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->createOne();
|
||||
|
||||
$response = $this->get(route('api.artistresource.show', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters));
|
||||
|
||||
$artistResource->unsetRelations();
|
||||
|
||||
$response->assertJson(
|
||||
json_decode(
|
||||
json_encode(
|
||||
(new ArtistResourceResource($artistResource, new Query($parameters)))
|
||||
->response()
|
||||
->getData()
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Show Endpoint shall support constrained eager loading of resources by site.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResourcesBySite(): void
|
||||
{
|
||||
$siteFilter = ResourceSite::getRandomInstance();
|
||||
|
||||
$parameters = [
|
||||
FilterParser::param() => [
|
||||
ExternalResource::ATTRIBUTE_SITE => $siteFilter->description,
|
||||
],
|
||||
IncludeParser::param() => ArtistResource::RELATION_RESOURCE,
|
||||
];
|
||||
|
||||
$artistResource = ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->createOne();
|
||||
|
||||
$response = $this->get(route('api.artistresource.show', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters));
|
||||
|
||||
$artistResource->unsetRelations()->load([
|
||||
ArtistResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) {
|
||||
$query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value);
|
||||
},
|
||||
]);
|
||||
|
||||
$response->assertJson(
|
||||
json_decode(
|
||||
json_encode(
|
||||
(new ArtistResourceResource($artistResource, new Query($parameters)))
|
||||
->response()
|
||||
->getData()
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Http\Api\Pivot\Wiki\ArtistResource;
|
||||
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\Wiki\Artist;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Pivots\Wiki\ArtistResource;
|
||||
use Illuminate\Foundation\Testing\WithoutEvents;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Class ArtistResourceStoreTest.
|
||||
*/
|
||||
class ArtistResourceStoreTest extends TestCase
|
||||
{
|
||||
use WithoutEvents;
|
||||
|
||||
/**
|
||||
* The Artist Resource Store Destroy Endpoint shall be protected by sanctum.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testProtected(): void
|
||||
{
|
||||
$artistResource = ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->makeOne();
|
||||
|
||||
$response = $this->post(route('api.artistresource.store', $artistResource->toArray()));
|
||||
|
||||
$response->assertUnauthorized();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Store Endpoint shall forbid users without the create artist & create resource permissions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testForbidden(): void
|
||||
{
|
||||
$artistResource = ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->makeOne();
|
||||
|
||||
$user = User::factory()->createOne();
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->post(route('api.artistresource.store', $artistResource->toArray()));
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Store Endpoint shall require artist and resource fields.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRequiredFields(): void
|
||||
{
|
||||
$user = User::factory()->withPermissions(['create artist', 'create external resource'])->createOne();
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->post(route('api.artistresource.store'));
|
||||
|
||||
$response->assertJsonValidationErrors([
|
||||
ArtistResource::ATTRIBUTE_ARTIST,
|
||||
ArtistResource::ATTRIBUTE_RESOURCE,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Store Endpoint shall create an artist resource.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCreate(): void
|
||||
{
|
||||
$parameters = array_merge(
|
||||
ArtistResource::factory()->raw(),
|
||||
[ArtistResource::ATTRIBUTE_ARTIST => Artist::factory()->createOne()->getKey()],
|
||||
[ArtistResource::ATTRIBUTE_RESOURCE => ExternalResource::factory()->createOne()->getKey()],
|
||||
);
|
||||
|
||||
$user = User::factory()->withPermissions(['create artist', 'create external resource'])->createOne();
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->post(route('api.artistresource.store', $parameters));
|
||||
|
||||
$response->assertCreated();
|
||||
static::assertDatabaseCount(ArtistResource::TABLE, 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Http\Api\Pivot\Wiki\ArtistResource;
|
||||
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\Wiki\Artist;
|
||||
use App\Models\Wiki\ExternalResource;
|
||||
use App\Pivots\Wiki\ArtistResource;
|
||||
use Illuminate\Foundation\Testing\WithoutEvents;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Class ArtistResourceUpdateTest.
|
||||
*/
|
||||
class ArtistResourceUpdateTest extends TestCase
|
||||
{
|
||||
use WithoutEvents;
|
||||
|
||||
/**
|
||||
* The Artist Resource Update Destroy Endpoint shall be protected by sanctum.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testProtected(): void
|
||||
{
|
||||
$artistResource = ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->createOne();
|
||||
|
||||
$parameters = ArtistResource::factory()->raw();
|
||||
|
||||
$response = $this->put(route('api.artistresource.update', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters));
|
||||
|
||||
$response->assertUnauthorized();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Update Endpoint shall forbid users without the update artist & update resource permissions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testForbidden(): void
|
||||
{
|
||||
$artistResource = ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->createOne();
|
||||
|
||||
$parameters = ArtistResource::factory()->raw();
|
||||
|
||||
$user = User::factory()->createOne();
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->put(route('api.artistresource.update', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters));
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Artist Resource Update Endpoint shall update an artist resource.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testUpdate(): void
|
||||
{
|
||||
$artistResource = ArtistResource::factory()
|
||||
->for(Artist::factory())
|
||||
->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE)
|
||||
->createOne();
|
||||
|
||||
$parameters = ArtistResource::factory()->raw();
|
||||
|
||||
$user = User::factory()->withPermissions(['update artist', 'update external resource'])->createOne();
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->put(route('api.artistresource.update', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters));
|
||||
|
||||
$response->assertOk();
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,8 @@ class ThemeShowTest extends TestCase
|
||||
)
|
||||
->createOne();
|
||||
|
||||
$theme->unsetRelations()->load($includedPaths->all());
|
||||
|
||||
$response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters));
|
||||
|
||||
$response->assertJson(
|
||||
|
||||
Reference in New Issue
Block a user