Skip to content

Commit

Permalink
feat(smart-actions): added smart-actions support (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasalexandre9 authored Mar 9, 2022
1 parent 9a4bca1 commit bdef099
Show file tree
Hide file tree
Showing 23 changed files with 1,698 additions and 362 deletions.
657 changes: 312 additions & 345 deletions composer.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions routes/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use ForestAdmin\LaravelForestAdmin\Http\Controllers\ApiMapsController;
use ForestAdmin\LaravelForestAdmin\Http\Controllers\AuthController;
use ForestAdmin\LaravelForestAdmin\Http\Controllers\DispatchGateway;
use ForestAdmin\LaravelForestAdmin\Http\Controllers\SmartActionController;
use ForestAdmin\LaravelForestAdmin\Http\Middleware\ForestAuthorization;
use Illuminate\Support\Facades\Route;

Expand Down Expand Up @@ -42,6 +43,10 @@ function () {
Route::put('/{collection}/{id}/relationships/{association_name}', DispatchGateway::class)->name('forest.relationships.update');
Route::delete('/{collection}/{id}/relationships/{association_name}', DispatchGateway::class)->name('forest.relationships.dissociate');
Route::get('/{collection}/{id}/relationships/{association_name}/count', DispatchGateway::class)->name('forest.relationships.count');

// SMART ACTIONS
Route::post('/smart-actions/{action}', SmartActionController::class);
Route::post('/smart-actions/{action}/hooks/{hook}', SmartActionController::class);
}
);
}
Expand Down
3 changes: 2 additions & 1 deletion src/Auth/Guard/ForestUserFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use ForestAdmin\LaravelForestAdmin\Utils\Traits\FormatGuzzle;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;

/**
* Class ForestUserFactory
Expand Down Expand Up @@ -56,7 +57,7 @@ public function makePermissionToUser(ForestUser $forestUser, int $renderingId, b
foreach ($permissions['collections'][$collection][$type] as $key => $value) {
$value = $type === 'actions' ? $value['triggerEnabled'] : $value;
if ($value === true || (is_array($value) && in_array($forestUser->getKey(), $value, true))) {
$actions[] = $key;
$actions[] = $type === 'actions' ? Str::slug($key) : $key;
}
}
$method = $type === 'collection' ? 'addPermission' : 'addSmartActionPermission';
Expand Down
2 changes: 1 addition & 1 deletion src/Auth/Guard/Model/ForestUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public function addSmartActionPermission(string $key, array $values): ForestUser
*/
public function hasSmartActionPermission(string $key, string $action): bool
{
return in_array($action, $this->getSmartActionPermissions()[$key], true);
return in_array($action, $this->getSmartActionPermissions()->get($key, []), true);
}

/**
Expand Down
1 change: 0 additions & 1 deletion src/Facades/ChartApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use ForestAdmin\LaravelForestAdmin\Services\ChartApiResponse;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Facade;

/**
Expand Down
4 changes: 2 additions & 2 deletions src/ForestServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public function boot(Kernel $kernel): void
$kernel->pushMiddleware(ForestCors::class);

$this->app->bind('chart-api', fn() => new ChartApiResponse());
$this->app->bind('json-api', fn() => new JsonApiResponse());
$this->app->bind('forest-schema', fn() => new ForestSchemaInstrospection());
$this->app->bind('json-api', fn() => new JsonApiResponse());
}

/**
Expand All @@ -65,7 +65,7 @@ public function register(): void
[
'auth.guards.forest' => array_merge(
[
'driver' => 'forest-token',
'driver' => 'forest-token',
],
config('auth.guards.forest', [])
),
Expand Down
98 changes: 98 additions & 0 deletions src/Http/Controllers/SmartActionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php

namespace ForestAdmin\LaravelForestAdmin\Http\Controllers;

use ForestAdmin\LaravelForestAdmin\Services\SmartActions\SmartAction;
use ForestAdmin\LaravelForestAdmin\Utils\Traits\Schema;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\JsonResponse;
use Illuminate\Routing\Route;
use Illuminate\Support\Str;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

/**
* Class SmartActionController
*
* @package Laravel-forestadmin
* @license GNU https://www.gnu.org/licences/licences.html
* @link https://github.com/ForestAdmin/laravel-forestadmin
*/
class SmartActionController extends ForestController
{
/**
* @var Model $collection
*/
protected Model $collection;

/**
* @var SmartAction
*/
protected SmartAction $smartAction;

/**
* @param Route $route
* @return JsonResponse
* @throws \Exception
*/
public function __invoke(Route $route)
{
[$collection, $name] = explode('_', $route->parameter('action'));
$this->collection = Schema::getModel($collection);
$this->smartAction = $this->collection->getSmartAction($name);

if ($type = $route->parameter('hook')) {
return $type === 'load' ? $this->executeLoadHook() : $this->executeChangeHook();
} else {
return $this->executeAction();
}
}

/**
* @return JsonResponse
* @throws AuthorizationException
*/
public function executeAction(): JsonResponse
{
$this->authorize('smartAction', [$this->collection, Str::slug($this->smartAction->getKey())]);

return response()->json(
call_user_func($this->smartAction->getExecute())
);
}

/**
* @return JsonResponse
*/
public function executeLoadHook(): JsonResponse
{
return response()->json(
[
'fields' => array_values(
$this->smartAction
->getLoad()
->call($this->smartAction)
)
]
);
}

/**
* @return JsonResponse
* @throws \Exception
*/
public function executeChangeHook(): JsonResponse
{
return response()->json(
[
'fields' => array_values(
$this->smartAction
->getChange(request()->input('data.attributes.changed_field'))
->call($this->smartAction->mergeRequestFields(request()->input('data.attributes.fields')))
)
]
);
}
}
11 changes: 11 additions & 0 deletions src/Policies/PermissionPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,17 @@ public function export(ForestUser $forestUser, $collection)
return $forestUser->hasPermission($this->getCollectionName($collection), 'exportEnabled');
}

/**
* @param ForestUser $forestUser
* @param $collection
* @param $action
* @return bool
*/
public function smartAction(ForestUser $forestUser, $collection, $action)
{
return $forestUser->hasSmartActionPermission($this->getCollectionName($collection), $action);
}

/**
* @param mixed $collection
* @return string
Expand Down
16 changes: 16 additions & 0 deletions src/Schema/ForestModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ public function serialize(): array
'only_for_relationships' => $this->isOnlyForRelationships(),
'pagination_type' => $this->getPaginationType(),
'fields' => $this->getFields(),
'actions' => $this->getSmartActions(),
];
}

Expand All @@ -136,6 +137,21 @@ public function getFields(): array
return $fields->values()->toArray();
}

/**
* @return array
* @throws Exception
*/
public function getSmartActions(): array
{
$schemaSmartActions = [];
$smartActions = method_exists($this->model, 'smartActions') ? $this->model->smartActions() : [];
foreach ($smartActions as $smartAction) {
$schemaSmartActions[] = $smartAction->serialize();
}

return $schemaSmartActions;
}

/**
* @return string
*/
Expand Down
32 changes: 30 additions & 2 deletions src/Schema/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Response;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\File;
Expand Down Expand Up @@ -129,13 +130,17 @@ private function serialize(): array
$included = [];

foreach ($schema['collections'] as $collection) {
$collectionActions = $collection['actions'];
unset($collection['actions']);
$included[] = $this->getActionsByCollection($collectionActions, true);

$data[] = [
'id' => $collection['name'],
'type' => 'collections',
'attributes' => $collection,
'relationships' => [
'actions' => [
'data' => []
'data' => $this->getActionsByCollection($collectionActions)
],
'segments' => [
'data' => []
Expand All @@ -146,11 +151,34 @@ private function serialize(): array

return [
'data' => $data,
'included' => $included,
'included' => array_merge(...$included),
'meta' => $schema['meta'],
];
}

/**
* @param array $data
* @param bool $withAttributes
* @return array
*/
private function getActionsByCollection(array $data, bool $withAttributes = false): array
{
$actions = [];

foreach ($data as $value) {
$action = [
'id' => $value['id'],
'type' => 'actions',
];
if ($withAttributes) {
$action['attributes'] = $value;
}
$actions[] = $action;
}

return $actions;
}

/**
* Fetch all files in the model directory
* @return Collection
Expand Down
30 changes: 30 additions & 0 deletions src/Services/Concerns/ForestCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace ForestAdmin\LaravelForestAdmin\Services\Concerns;

use ForestAdmin\LaravelForestAdmin\Exceptions\ForestException;
use ForestAdmin\LaravelForestAdmin\Services\SmartActions\SmartAction;
use Illuminate\Support\Collection;

/**
* Class ForestCollection
*
Expand All @@ -28,4 +32,30 @@ public function searchFields(): array
{
return [];
}

/**
* @return Collection
* @codeCoverageIgnore
*/
public function smartActions(): Collection
{
return collect();
}

/**
* @param string $name
* @return SmartAction
*/
public function getSmartAction(string $name): SmartAction
{
$smartAction = $this->smartActions()->first(
fn ($item) => $item->getKey() === $name
);

if (null !== $smartAction) {
return $smartAction;
} else {
throw new ForestException("There is no smart-action $name");
}
}
}
1 change: 1 addition & 0 deletions src/Services/JsonApiResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use ForestAdmin\LaravelForestAdmin\Facades\ForestSchema;
use ForestAdmin\LaravelForestAdmin\Serializer\JsonApiSerializer;
use ForestAdmin\LaravelForestAdmin\Transformers\BaseTransformer;
use ForestAdmin\LaravelForestAdmin\Transformers\ChartTransformer;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection as BaseCollection;
Expand Down
Loading

0 comments on commit bdef099

Please sign in to comment.