Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authorization #17

Draft
wants to merge 5 commits into
base: development
Choose a base branch
from
Draft
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
6 changes: 5 additions & 1 deletion src/Concerns/BehaveAsPanel.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

namespace DigitalCreative\Jaqen\Concerns;

use DigitalCreative\Jaqen\Services\Fields\Fields\FieldsCollection;

interface BehaveAsPanel
{
public function getFields(): array;

public function getFields(): FieldsCollection;

}
51 changes: 0 additions & 51 deletions src/Fields/Panel.php

This file was deleted.

16 changes: 16 additions & 0 deletions src/Http/Middlewares/Authorize.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace DigitalCreative\Jaqen\Http\Middlewares;

use DigitalCreative\Jaqen\Http\Requests\BaseRequest;
use Illuminate\Http\Response;

class Authorize
{

public function handle(BaseRequest $request, callable $next): Response
{
return $request->resourceInstance() ? $next($request) : abort(403);
}

}
7 changes: 0 additions & 7 deletions src/Http/Requests/BaseRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

namespace DigitalCreative\Jaqen\Http\Requests;

use DigitalCreative\Jaqen\Jaqen;
use DigitalCreative\Jaqen\Services\ResourceManager\AbstractResource;
use DigitalCreative\Jaqen\Services\ResourceManager\Http\Requests\StoreResourceRequest;
use DigitalCreative\Jaqen\Services\ResourceManager\Http\Requests\UpdateResourceRequest;
use Illuminate\Foundation\Http\FormRequest;
Expand All @@ -23,11 +21,6 @@ public function rules(): array
return [];
}

public function resourceInstance(): AbstractResource
{
return Jaqen::getInstance()->resourceForRequest($this);
}

public function isCreate(): bool
{
return $this instanceof StoreResourceRequest
Expand Down
5 changes: 4 additions & 1 deletion src/Services/Fields/Fields/AbstractField.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

namespace DigitalCreative\Jaqen\Services\Fields\Fields;

use DigitalCreative\Jaqen\Concerns\BehaveAsPanel;
use DigitalCreative\Jaqen\Http\Requests\BaseRequest;
use DigitalCreative\Jaqen\Services\Fields\Traits\ResolveRulesTrait;
use DigitalCreative\Jaqen\Services\ResourceManager\AbstractFilter;
use DigitalCreative\Jaqen\Services\ResourceManager\AbstractResource;
use DigitalCreative\Jaqen\Traits\AuthorizableTrait;
use DigitalCreative\Jaqen\Traits\MakeableTrait;
use DigitalCreative\Jaqen\Traits\ResolveValueTrait;
use Illuminate\Contracts\Support\Arrayable;
Expand All @@ -21,6 +23,7 @@ abstract class AbstractField implements JsonSerializable, Arrayable, Potentially
use ResolveRulesTrait;
use MakeableTrait;
use ResolveValueTrait;
use AuthorizableTrait;

public string $label;
public string $attribute;
Expand Down Expand Up @@ -149,7 +152,7 @@ public function jsonSerialize(): array
return array_merge([
'label' => $this->label,
'attribute' => $this->attribute,
'value' => $this->value,
'value' => $this instanceof BehaveAsPanel ? $this->getFields() : value($this->value),
'component' => $this->component(),
'additionalInformation' => $this->resolveAdditionalInformation(),
], $this->resolveData());
Expand Down
13 changes: 13 additions & 0 deletions src/Services/Fields/Fields/FieldsCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use DigitalCreative\Jaqen\Concerns\WithCustomUpdate;
use DigitalCreative\Jaqen\Concerns\WithEvents;
use DigitalCreative\Jaqen\Http\Requests\BaseRequest;
use DigitalCreative\Jaqen\Services\ResourceManager\AbstractFilter;
use DigitalCreative\Jaqen\Services\ResourceManager\AbstractResource;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Resources\PotentiallyMissing;
Expand All @@ -16,6 +17,18 @@
class FieldsCollection extends Collection
{

public function boot(AbstractResource|AbstractFilter $resource, BaseRequest $request): self
{
return $this->each(fn(AbstractField $field) => $field->boot($resource, $request));
}

public function authorized(): self
{
return $this
->filter(fn(AbstractField $field) => $field->isAuthorizedToSee())
->values();
}

public function resolveData(): array
{
return $this->filter(fn(PotentiallyMissing $field) => !$field->isMissing())
Expand Down
27 changes: 27 additions & 0 deletions src/Services/Fields/Fields/Panel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types = 1);

namespace DigitalCreative\Jaqen\Services\Fields\Fields;

use Closure;
use DigitalCreative\Jaqen\Concerns\BehaveAsPanel;

class Panel extends Proxy implements BehaveAsPanel
{

private Closure|array $fields;

public function __construct(string $label, array|callable $fields = [])
{
parent::__construct($label);

$this->fields = $fields;
}

public function getFields(): FieldsCollection
{
return once(fn() => FieldsCollection::wrap(value($this->fields))->authorized());
}

}
48 changes: 48 additions & 0 deletions src/Services/Fields/Fields/Proxy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types = 1);

namespace DigitalCreative\Jaqen\Services\Fields\Fields;

use DigitalCreative\Jaqen\Http\Requests\BaseRequest;
use Illuminate\Database\Eloquent\Model;

abstract class Proxy extends AbstractField
{

protected abstract function getFields(): FieldsCollection;

public function resolveValueFromModel(Model $model, BaseRequest $request): self
{
$this->getFields()->each(fn(AbstractField $field) => $field->resolveValueFromModel($model, $request));

return $this;
}

public function resolveValueFromRequest(BaseRequest $request): self
{
$this->getFields()->each(fn(AbstractField $field) => $field->resolveValueFromRequest($request));

return $this;
}

public function resolveValueFromArray(array $data, BaseRequest $request): self
{
$this->getFields()->each(fn(AbstractField $field) => $field->resolveValueFromArray($data, $request));

return $this;
}

public function resolveValueFromDefaults(BaseRequest $request): self
{
$this->getFields()->each(fn(AbstractField $field) => $field->resolveValueFromDefaults($request));

return $this;
}

public function boot($resource, BaseRequest $request): void
{
$this->getFields()->each(fn(AbstractField $field) => $field->boot($resource, $request));
}

}
3 changes: 2 additions & 1 deletion src/Services/Fields/FieldsServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public function boot(): void
*/
Route::group([ 'prefix' => '/jaqen-api/fields', 'as' => 'jaqen.fields.' ], function (Router $router) {

$router->get('/belongs-to/{resource}/{field}', [ BelongsToController::class, 'searchBelongsTo' ])->name('belongs-to');
$router->get('/belongs-to/{resource}/{field}', [ BelongsToController::class, 'searchBelongsTo' ])
->name('belongs-to');

});
}
Expand Down
6 changes: 6 additions & 0 deletions src/Services/Fields/Http/Controllers/BelongsToController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,23 @@
use DigitalCreative\Jaqen\Fields\Relationships\BelongsToField;
use DigitalCreative\Jaqen\Http\Requests\BelongsToResourceRequest;
use DigitalCreative\Jaqen\Services\ResourceManager\Http\Controllers\Controller;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Str;
use Throwable;

class BelongsToController extends Controller
{

/**
* @throws AuthorizationException|Throwable
*/
public function searchBelongsTo(BelongsToResourceRequest $request): JsonResponse
{

$resource = $this->resourceManager->resourceForRequest($request);
$resource->authorizeTo('view');

$fieldAttribute = Str::of($request->route('field'))->before('_id')->__toString();

Expand Down
80 changes: 50 additions & 30 deletions src/Services/Fields/Traits/ResolveFieldsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use DigitalCreative\Jaqen\Services\Fields\Fields\FieldsCollection;
use DigitalCreative\Jaqen\Services\Fields\FieldsData;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use LogicException;
use RuntimeException;
Expand Down Expand Up @@ -57,21 +58,16 @@ public function resolveValidatedFields(BaseRequest $request): array

/**
* Resolve fields and remove every field that is not necessary for this given request
*
* @param BaseRequest $request
* @param string|null $for
*
* @return FieldsCollection
*/
public function resolveFields(BaseRequest $request, ?string $for = null): FieldsCollection
{
return once(function () use ($request, $for) {

/**
* First step is to determine if the fields should be retrieved from fields, fieldsFor* or invokable
*/
$for = $for ?? Str::camel($request->input('fieldsFor', 'fields'));

$only = $request->input('only');
$except = $request->input('except');

/**
* If fields has been set through ->fieldsFor()
*/
Expand Down Expand Up @@ -125,36 +121,60 @@ public function resolveFields(BaseRequest $request, ?string $for = null): Fields

}

return (new FieldsCollection($fields))
->when($request->isStoringResourceToDatabase(), function (FieldsCollection $fields) {
return $this->filterFields($request, $fields);

return $fields->flatMap(function (AbstractField $field) {
});
}

if ($field instanceof BehaveAsPanel) {
private function filterFields(BaseRequest $request, array $fields): FieldsCollection
{
$only = $request->input('only');
$except = $request->input('except');

return $field->getFields();
return (new FieldsCollection($fields))
->when($request->isStoringResourceToDatabase(), function (FieldsCollection $fields) {

}
return $fields->flatMap(function (AbstractField $field) {

return [ $field ];
if ($field instanceof BehaveAsPanel) {

});
return $field->getFields();

})
->when($only, function (FieldsCollection $fields, string $only) {
return $fields->filter(
fn(AbstractField $field) => $this->stringContains($only, $field->attribute)
);
})
->when($except, function (FieldsCollection $fields, string $except) {
return $fields->filter(
fn(AbstractField $field) => !$this->stringContains($except, $field->attribute)
);
})
->each(fn(AbstractField $field) => $field->boot($this, $request))
->values();
}

});
return [ $field ];

});

})
->when($request->isSchemaFetching(), function (FieldsCollection $fields) use ($request) {

$fields->each(function (AbstractField $field) use ($request) {

$field->resolveValueFromDefaults($request);

});

return $fields;

})
->when($only, function (FieldsCollection $fields, string $only) {
return $fields->filter(
fn(AbstractField $field) => $this->stringContains($only, $field->attribute)
);
})
->when($except, function (FieldsCollection $fields, string $except) {
return $fields->filter(
fn(AbstractField $field) => !$this->stringContains($except, $field->attribute)
);
})
->authorized()
->boot($this, $request);
}

private function authorizedFields(Collection $collection): Collection
{
return $collection->filter(fn(AbstractField $field) => $field->isAuthorizedToSee());
}

private function stringContains(string $items, string $attribute): bool
Expand Down
Loading