Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Console/stubs/action.stub
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class {{ class }} extends RestAction
* @param \Lomkit\Rest\Http\Requests\RestRequest $request
* @return array
*/
public function fields(\Lomkit\Rest\Http\Requests\RestRequest $request)
public function fields(\Lomkit\Rest\Http\Requests\RestRequest $request): array
{
return [
'id' => [
Expand Down
2 changes: 1 addition & 1 deletion src/Console/stubs/instruction.stub
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class {{ class }} extends RestInstruction
* @param \Lomkit\Rest\Http\Requests\RestRequest $request
* @return array
*/
public function fields(\Lomkit\Rest\Http\Requests\RestRequest $request)
public function fields(\Lomkit\Rest\Http\Requests\RestRequest $request): array
{
return [
'id' => [
Expand Down
3 changes: 3 additions & 0 deletions src/Documentation/Schemas/RequestBody.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ public function generateSearch(Controller $controller): RequestBody
],
],
],
'gates' => [
'create',
],
'page' => 2,
'limit' => 10,
]
Expand Down
1 change: 1 addition & 0 deletions src/Http/Requests/SearchRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public function searchRules(Resource $resource, $prefix = '', $isRootSearchRules
[
'limit' => ['sometimes', 'integer', Rule::in($resource->getLimits($this))],
'page' => ['sometimes', 'integer'],
'gates' => ['sometimes', 'array', Rule::in(['viewAny', 'view', 'create', 'update', 'delete', 'restore', 'forceDelete'])],
],
$isRootSearchRules ? ['includes' => ['sometimes', 'array']] : [],
$isRootSearchRules ? $this->includesRules($resource) : [],
Expand Down
4 changes: 2 additions & 2 deletions src/Http/Resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public function getAuthorizationCacheKey(RestRequest $request, string $identifie
/**
* Determine for how much time the authorization cache should be keeped.
*
* @return \DateTimeInterface|\DateInterval|float|int|null
* @return \DateTimeInterface|\DateInterval
*/
public function cacheAuthorizationFor()
{
Expand Down Expand Up @@ -172,7 +172,7 @@ public function getResourceCacheKey(RestRequest $request, string $identifier)
/**
* Determine for how much time the resource cache should be keeped.
*
* @return \DateTimeInterface|\DateInterval|float|int|null
* @return \DateTimeInterface|\DateInterval
*/
public function cacheResourceFor()
{
Expand Down
47 changes: 24 additions & 23 deletions src/Http/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Illuminate\Database\Eloquent\Relations\Pivot;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Str;
use Lomkit\Rest\Http\Requests\RestRequest;
use Lomkit\Rest\Relations\Relation;
Expand All @@ -31,15 +30,15 @@ public function resource(Resource $resource)
});
}

protected function buildGatesForModel(Model $model)
protected function buildGatesForModel(Model $model, Resource $resource, array $gates)
{
return [
config('rest.automatic_gates.names.authorized_to_view') => Gate::allows('view', $model),
config('rest.automatic_gates.names.authorized_to_update') => Gate::allows('update', $model),
config('rest.automatic_gates.names.authorized_to_delete') => Gate::allows('delete', $model),
config('rest.automatic_gates.names.authorized_to_restore') => Gate::allows('restore', $model),
config('rest.automatic_gates.names.authorized_to_force_delete') => Gate::allows('forceDelete', $model),
];
return array_merge(
in_array('view', $gates) ? [config('rest.automatic_gates.names.authorized_to_view') => $resource->authorizedTo('view', $model)] : [],
in_array('update', $gates) ? [config('rest.automatic_gates.names.authorized_to_update') => $resource->authorizedTo('update', $model)] : [],
in_array('delete', $gates) ? [config('rest.automatic_gates.names.authorized_to_delete') => $resource->authorizedTo('delete', $model)] : [],
in_array('restore', $gates) ? [config('rest.automatic_gates.names.authorized_to_restore') => $resource->authorizedTo('restore', $model)] : [],
in_array('forceDelete', $gates) ? [config('rest.automatic_gates.names.authorized_to_force_delete') => $resource->authorizedTo('forceDelete', $model)] : [],
);
}

public function modelToResponse(Model $model, Resource $resource, array $requestArray, Relation $relation = null)
Expand All @@ -54,26 +53,26 @@ public function modelToResponse(Model $model, Resource $resource, array $request
collect($model->attributesToArray())
->only(
array_merge(
isset($requestArray['selects']) ?
collect($requestArray['selects'])->pluck('field')->toArray() :
isset($currentRequestArray['selects']) ?
collect($currentRequestArray['selects'])->pluck('field')->toArray() :
$resource->getFields(app()->make(RestRequest::class)),
// Here we add the aggregates
collect($requestArray['aggregates'] ?? [])
collect($currentRequestArray['aggregates'] ?? [])
->map(function ($aggregate) {
return Str::snake($aggregate['relation']).'_'.$aggregate['type'].(isset($aggregate['field']) ? '_'.$aggregate['field'] : '');
})
->toArray()
)
)
->when($resource->isAutomaticGatingEnabled(), function ($attributes) use ($model) {
->when($resource->isAutomaticGatingEnabled() && isset($currentRequestArray['gates']), function ($attributes) use ($currentRequestArray, $resource, $model) {
return $attributes->put(
config('rest.automatic_gates.key'),
$this->buildGatesForModel($model)
$this->buildGatesForModel($model, $resource, $currentRequestArray['gates'])
);
})
->toArray(),
collect($model->getRelations())
->mapWithKeys(function ($modelRelation, $relationName) use ($requestArray, $relation, $resource) {
->mapWithKeys(function ($modelRelation, $relationName) use ($requestArray, $currentRequestArray, $relation, $resource) {
$key = Str::snake($relationName);

if (is_null($modelRelation)) {
Expand All @@ -90,7 +89,7 @@ public function modelToResponse(Model $model, Resource $resource, array $request

$relationConcrete = $resource->relation($relationName);
$relationResource = $relationConcrete->resource();
$requestArrayRelation = collect($requestArray['includes'])
$requestArrayRelation = collect($currentRequestArray['includes'] ?? [])
->first(function ($include) use ($relationName) {
return preg_match('/(?:\.\b)?'.$relationName.'\b/', $include['relation']);
});
Expand Down Expand Up @@ -128,9 +127,9 @@ public function toResponse($request)
$this->responsable->perPage(),
$this->responsable->currentPage(),
$this->responsable->getOptions(),
$this->resource->isAutomaticGatingEnabled() ? [
$this->resource->isAutomaticGatingEnabled() && in_array('create', $request->input('gates', [])) ? [
config('rest.automatic_gates.key') => [
config('rest.automatic_gates.names.authorized_to_create') => Gate::allows('create', $this->resource::newModel()::class),
config('rest.automatic_gates.names.authorized_to_create') => $this->resource->authorizedTo('create', $this->resource::newModel()::class),
],
] : []
);
Expand All @@ -148,11 +147,13 @@ public function toResponse($request)

return [
'data' => $data ?? $this->map($this->responsable, $this->modelToResponse($this->responsable, $this->resource, $request->input())),
'meta' => [
config('rest.automatic_gates.key') => [
config('rest.automatic_gates.names.authorized_to_create') => Gate::allows('create', $this->resource::newModel()::class),
],
],
'meta' => array_merge(
$this->resource->isAutomaticGatingEnabled() && in_array('create', $request->input('gates', [])) ? [
config('rest.automatic_gates.key') => [
config('rest.automatic_gates.names.authorized_to_create') => $this->resource->authorizedTo('create', $this->resource::newModel()::class),
],
] : []
),
];
}

Expand Down
83 changes: 51 additions & 32 deletions tests/Feature/Controllers/AutomaticGatingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
use Lomkit\Rest\Http\Requests\RestRequest;
use Lomkit\Rest\Tests\Feature\TestCase;
use Lomkit\Rest\Tests\Support\Database\Factories\BelongsToManyRelationFactory;
use Lomkit\Rest\Tests\Support\Database\Factories\HasManyRelationFactory;
use Lomkit\Rest\Tests\Support\Database\Factories\ModelFactory;
use Lomkit\Rest\Tests\Support\Models\BelongsToManyRelation;
use Lomkit\Rest\Tests\Support\Models\HasManyRelation;
use Lomkit\Rest\Tests\Support\Models\Model;
use Lomkit\Rest\Tests\Support\Policies\CreatePolicy;
use Lomkit\Rest\Tests\Support\Policies\DeletePolicy;
Expand All @@ -32,7 +34,7 @@ public function test_searching_automatic_gated_resource(): void
$response = $this->post(
'/api/automatic-gating/search',
[

'gates' => ['create', 'view', 'update', 'delete', 'forceDelete', 'restore'],
],
['Accept' => 'application/json']
);
Expand Down Expand Up @@ -92,7 +94,7 @@ public function test_searching_automatic_gated_resource_with_create_policy(): vo
$response = $this->post(
'/api/automatic-gating/search',
[

'gates' => ['create', 'view'],
],
['Accept' => 'application/json']
);
Expand All @@ -105,10 +107,6 @@ public function test_searching_automatic_gated_resource_with_create_policy(): vo
[
'gates' => [
'authorized_to_view' => false,
'authorized_to_update' => false,
'authorized_to_delete' => false,
'authorized_to_restore' => false,
'authorized_to_force_delete' => false,
],
],
]
Expand All @@ -128,7 +126,7 @@ public function test_searching_automatic_gated_resource_with_view_policy(): void
$response = $this->post(
'/api/automatic-gating/search',
[

'gates' => ['view', 'create'],
],
['Accept' => 'application/json']
);
Expand All @@ -141,10 +139,6 @@ public function test_searching_automatic_gated_resource_with_view_policy(): void
[
'gates' => [
'authorized_to_view' => true,
'authorized_to_update' => false,
'authorized_to_delete' => false,
'authorized_to_restore' => false,
'authorized_to_force_delete' => false,
],
],
]
Expand All @@ -164,7 +158,7 @@ public function test_searching_automatic_gated_resource_with_update_policy(): vo
$response = $this->post(
'/api/automatic-gating/search',
[

'gates' => ['update'],
],
['Accept' => 'application/json']
);
Expand All @@ -176,17 +170,13 @@ public function test_searching_automatic_gated_resource_with_update_policy(): vo
[
[
'gates' => [
'authorized_to_view' => false,
'authorized_to_update' => true,
'authorized_to_delete' => false,
'authorized_to_restore' => false,
'authorized_to_force_delete' => false,
],
],
]
);
$response->assertJson(
['meta' => ['gates' => ['authorized_to_create' => false]]]
['meta' => []]
);
}

Expand All @@ -200,7 +190,7 @@ public function test_searching_automatic_gated_resource_with_delete_policy(): vo
$response = $this->post(
'/api/automatic-gating/search',
[

'gates' => ['create', 'delete'],
],
['Accept' => 'application/json']
);
Expand All @@ -212,11 +202,7 @@ public function test_searching_automatic_gated_resource_with_delete_policy(): vo
[
[
'gates' => [
'authorized_to_view' => false,
'authorized_to_update' => false,
'authorized_to_delete' => true,
'authorized_to_restore' => false,
'authorized_to_force_delete' => false,
],
],
]
Expand All @@ -236,7 +222,7 @@ public function test_searching_automatic_gated_resource_with_restore_policy(): v
$response = $this->post(
'/api/automatic-gating/search',
[

'gates' => ['restore', 'view'],
],
['Accept' => 'application/json']
);
Expand All @@ -249,16 +235,13 @@ public function test_searching_automatic_gated_resource_with_restore_policy(): v
[
'gates' => [
'authorized_to_view' => false,
'authorized_to_update' => false,
'authorized_to_delete' => false,
'authorized_to_restore' => true,
'authorized_to_force_delete' => false,
],
],
]
);
$response->assertJson(
['meta' => ['gates' => ['authorized_to_create' => false]]]
['meta' => []]
);
}

Expand All @@ -272,7 +255,7 @@ public function test_searching_automatic_gated_resource_with_force_delete_policy
$response = $this->post(
'/api/automatic-gating/search',
[

'gates' => ['forceDelete', 'create'],
],
['Accept' => 'application/json']
);
Expand All @@ -284,10 +267,6 @@ public function test_searching_automatic_gated_resource_with_force_delete_policy
[
[
'gates' => [
'authorized_to_view' => false,
'authorized_to_update' => false,
'authorized_to_delete' => false,
'authorized_to_restore' => false,
'authorized_to_force_delete' => true,
],
],
Expand Down Expand Up @@ -316,11 +295,15 @@ public function test_searching_automatic_gated_resource_with_belongs_to_many_rel
'includes' => [
[
'relation' => 'belongsToManyRelation',
'gates' => ['view'],
],
],
'sorts' => [
['field' => 'id', 'direction' => 'asc'],
],
'gates' => [
'view', 'update', 'create', 'delete', 'restore', 'forceDelete',
],
],
['Accept' => 'application/json']
);
Expand Down Expand Up @@ -368,8 +351,44 @@ public function test_searching_automatic_gated_resource_with_belongs_to_many_rel
],
]
);
$this->assertArrayNotHasKey(
'gates',
$response->json('data.0.belongs_to_many_relation.0')
);
$response->assertJson(
['meta' => ['gates' => ['authorized_to_create' => true]]]
);
}

public function test_searching_automatic_gated_resource_with_not_requested_includes_gates(): void
{
ModelFactory::new()
->count(10)
->has(
HasManyRelationFactory::new()
->count(10)
)
->create();

Gate::policy(Model::class, GreenPolicy::class);
Gate::policy(HasManyRelation::class, GreenPolicy::class);

$response = $this->post(
'/api/automatic-gating/search',
[
'includes' => [
[
'relation' => 'hasManyRelation',
],
],
'gates' => ['view', 'create', 'update', 'delete', 'restore', 'forceDelete'],
],
['Accept' => 'application/json']
);

$this->assertArrayNotHasKey(
'gates',
$response->json('data.0.has_many_relation.0')
);
}
}
Loading