-
+
-
+ >
-
+
-
@@ -117,7 +212,9 @@ const API_OPTIONS = {
export default {
name: 'TreeView',
-
+ components: {
+ TreeSlug: () => import(/* webpackChunkName: "tree-slug" */'app/components/tree-slug/tree-slug'),
+ },
props: {
store: {
type: Object,
@@ -168,6 +265,10 @@ export default {
type: Boolean,
default: false,
},
+ previewConfig: {
+ type: Object,
+ default: () => ({}),
+ },
search: {
type: String,
default: '',
@@ -324,6 +425,7 @@ export default {
relation: {
menu: this.menu,
canonical: this.canonical,
+ slug_path: this.node?.meta?.relation?.slug_path,
},
},
});
diff --git a/src/Controller/TreeController.php b/src/Controller/TreeController.php
index 5dd48ca04..fbf6053ac 100644
--- a/src/Controller/TreeController.php
+++ b/src/Controller/TreeController.php
@@ -17,6 +17,7 @@
use BEdita\SDK\BEditaClientException;
use BEdita\WebTools\ApiClientProvider;
use Cake\Cache\Cache;
+use Cake\Http\Response;
use Cake\Utility\Hash;
use Psr\Log\LogLevel;
@@ -25,6 +26,16 @@
*/
class TreeController extends AppController
{
+ /**
+ * @inheritDoc
+ */
+ public function initialize(): void
+ {
+ parent::initialize();
+
+ $this->Security->setConfig('unlockedActions', ['slug']);
+ }
+
/**
* Get tree data.
* Use this for /tree?filter[roots]&... and /tree?filter[parent]=x&...
@@ -91,6 +102,47 @@ public function parents(string $type, string $id): void
$this->setSerialize(['parents']);
}
+ /**
+ * Saves the current slug
+ */
+ public function slug(): ?Response
+ {
+ $this->getRequest()->allowMethod(['post']);
+ $this->viewBuilder()->setClassName('Json');
+ $response = $error = null;
+ try {
+ $data = (array)$this->getRequest()->getData();
+ $body = [
+ 'data' => [
+ [
+ 'id' => (string)Hash::get($data, 'id'),
+ 'type' => (string)Hash::get($data, 'type'),
+ 'meta' => [
+ 'relation' => [
+ 'slug' => (string)Hash::get($data, 'slug'),
+ ],
+ ],
+ ],
+ ],
+ ];
+ $response = $this->apiClient->post(
+ sprintf('/folders/%s/relationships/children', (string)Hash::get($data, 'parent')),
+ json_encode($body)
+ );
+ // Clearing cache after successful save
+ Cache::clearGroup('tree', TreeCacheEventHandler::CACHE_CONFIG);
+ } catch (BEditaClientException $err) {
+ $error = $err->getMessage();
+ $this->log($error, 'error');
+ $this->set('error', $error);
+ }
+ $this->set('response', $response);
+ $this->set('error', $error);
+ $this->setSerialize(['response', 'error']);
+
+ return null;
+ }
+
/**
* Get tree data by query params.
* Use cache to store data.
@@ -239,7 +291,7 @@ function () use ($id, $type) {
*/
protected function fetchTreeData(array $query): array
{
- $fields = 'id,status,title';
+ $fields = 'id,status,title,perms,relation,slug_path';
$response = ApiClientProvider::getApiClient()->get('/folders', compact('fields') + $query);
$data = (array)Hash::get($response, 'data');
$meta = (array)Hash::get($response, 'meta');
@@ -261,6 +313,8 @@ protected function minimalData(array $fullData): array
if (empty($fullData)) {
return [];
}
+ $meta = (array)Hash::get($fullData, 'meta');
+ $meta['slug_path_compact'] = $this->slugPathCompact((array)Hash::get($meta, 'slug_path'));
return [
'id' => (string)Hash::get($fullData, 'id'),
@@ -269,6 +323,7 @@ protected function minimalData(array $fullData): array
'title' => (string)Hash::get($fullData, 'attributes.title'),
'status' => (string)Hash::get($fullData, 'attributes.status'),
],
+ 'meta' => $meta,
];
}
@@ -293,12 +348,31 @@ protected function minimalDataWithMeta(array $fullData): ?array
],
'meta' => [
'path' => (string)Hash::get($fullData, 'meta.path'),
+ 'slug_path' => (array)Hash::get($fullData, 'meta.slug_path'),
+ 'slug_path_compact' => $this->slugPathCompact((array)Hash::get($fullData, 'meta.slug_path')),
'relation' => [
'canonical' => (string)Hash::get($fullData, 'meta.relation.canonical'),
'depth_level' => (string)Hash::get($fullData, 'meta.relation.depth_level'),
'menu' => (string)Hash::get($fullData, 'meta.relation.menu'),
+ 'slug' => (string)Hash::get($fullData, 'meta.relation.slug'),
],
],
];
}
+
+ /**
+ * Get compact slug path.
+ *
+ * @param array $slugPath Slug path.
+ * @return string
+ */
+ protected function slugPathCompact(array $slugPath): string
+ {
+ $slugPathCompact = '';
+ foreach ($slugPath as $item) {
+ $slugPathCompact = sprintf('%s/%s', $slugPathCompact, (string)Hash::get($item, 'slug'));
+ }
+
+ return $slugPathCompact;
+ }
}
diff --git a/templates/Element/Form/trees.twig b/templates/Element/Form/trees.twig
index a9307ed75..fac8e32ee 100644
--- a/templates/Element/Form/trees.twig
+++ b/templates/Element/Form/trees.twig
@@ -49,12 +49,13 @@
class="mt-1"
relation-name={{ relationName }}
relation-label="{{ Layout.tr(relationName) }}"
- :object='{{ { id: object.id, type: object.type }|json_encode }}'
+ :object='{{ { id: object.id, type: object.type, uname: object.attributes.uname }|json_encode }}'
:multiple-choice={{ options.multiple }}
:user-roles="{{ user.roles|json_encode }}"
:has-permissions="{{ hasPermissions|json_encode }}"
:search="searchInPosition"
:search-in-position-active="searchInPositionActive"
+ :preview-config="{{ config('TreePreview')|json_encode }}"
@changed-parents="updatePositions">
diff --git a/tests/TestCase/Controller/TreeControllerTest.php b/tests/TestCase/Controller/TreeControllerTest.php
index 8b03950f7..c74591e96 100644
--- a/tests/TestCase/Controller/TreeControllerTest.php
+++ b/tests/TestCase/Controller/TreeControllerTest.php
@@ -104,6 +104,7 @@ public function fetchTreeData(array $query): array
* @covers ::node()
* @covers ::fetchNodeData()
* @covers ::minimalData()
+ * @covers ::slugPathCompact()
*/
public function testNode(): void
{
@@ -349,4 +350,90 @@ public function minData(array $data): array
$actual = $tree->minData([]);
static::assertEmpty($actual);
}
+
+ /**
+ * Test `slug` method
+ *
+ * @return void
+ * @covers ::initialize()
+ * @covers ::slug()
+ */
+ public function testSlug(): void
+ {
+ $this->setupApi();
+ $parent = $this->createTestFolder();
+ $response = $this->client->save('folders', [
+ 'title' => 'controller test folder child',
+ 'parent_id' => (int)Hash::get($parent, 'id'),
+ ]);
+ $child = $response['data'];
+ $parentId = (string)Hash::get($parent, 'id');
+ $childId = (string)Hash::get($child, 'id');
+ $type = (string)Hash::get($child, 'type');
+ $slug = 'test_slug';
+ $data = [
+ 'parent' => $parentId,
+ 'slug' => $slug,
+ 'type' => $type,
+ 'id' => $childId,
+ ];
+ $config = [
+ 'environment' => [
+ 'REQUEST_METHOD' => 'POST',
+ ],
+ 'post' => $data,
+ ];
+ $request = new ServerRequest($config);
+ $tree = new TreeController($request);
+ $tree->slug();
+ $actualResponse = $tree->viewBuilder()->getVar('response');
+ static::assertNotEmpty($actualResponse);
+ $actualError = $tree->viewBuilder()->getVar('error');
+ static::assertNull($actualError);
+ static::assertArrayHasKey('links', $actualResponse);
+ static::assertArrayHasKey('self', $actualResponse['links']);
+ static::assertArrayHasKey('home', $actualResponse['links']);
+ $this->assertNotEmpty($actualResponse['links']['self']);
+ $this->assertNotEmpty($actualResponse['links']['home']);
+ }
+
+ /**
+ * Test `slug` method on exception
+ *
+ * @return void
+ * @covers ::initialize()
+ * @covers ::slug()
+ */
+ public function testSlugException(): void
+ {
+ $this->setupApi();
+ $parent = $this->createTestFolder();
+ $response = $this->client->save('folders', [
+ 'title' => 'controller test folder child',
+ 'parent_id' => (int)Hash::get($parent, 'id'),
+ ]);
+ $child = $response['data'];
+ $childId = (string)Hash::get($child, 'id');
+ $type = (string)Hash::get($child, 'type');
+ $slug = 'test_slug';
+ $data = [
+ 'parent' => null,
+ 'slug' => $slug,
+ 'type' => $type,
+ 'id' => $childId,
+ ];
+ $config = [
+ 'environment' => [
+ 'REQUEST_METHOD' => 'POST',
+ ],
+ 'post' => $data,
+ ];
+ $request = new ServerRequest($config);
+ $tree = new TreeController($request);
+ $tree->slug();
+ $actualResponse = $tree->viewBuilder()->getVar('response');
+ $actualError = $tree->viewBuilder()->getVar('error');
+ static::assertEmpty($actualResponse);
+ static::assertNotEmpty($actualError);
+ }
}