Skip to content

Commit 91d84eb

Browse files
committed
Merge branch 'master' into refactor/js-to-vue
2 parents 8279086 + 08262b9 commit 91d84eb

22 files changed

+327
-69
lines changed

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"require": {
2424
"php": ">=8.3",
2525
"bedita/i18n": "^5.1.0",
26-
"bedita/web-tools": "^5.3",
26+
"bedita/web-tools": "^5.3.3",
2727
"cakephp/authentication": "^2.9",
2828
"cakephp/cakephp": "~4.5.0",
2929
"cakephp/plugin-installer": "^1.3",

config/app_local.example.php

+2
Original file line numberDiff line numberDiff line change
@@ -614,10 +614,12 @@
614614
// 'bearing' => 'integer',
615615
// 'pitch' => 'integer',
616616
// 'zoom' => 'integer',
617+
// 'caption' => 'richtext'
617618
// ],
618619
// 'videos' => [
619620
// 'controls' => 'boolean',
620621
// 'autoplay' => 'boolean',
622+
// 'caption' => 'richtext',
621623
// ],
622624
// ],
623625

config/version.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[Manager]
2-
version=5.4.2
2+
version=5.4.8

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bedita-manager",
3-
"version": "5.4.2",
3+
"version": "5.4.8",
44
"description": "BEdita Manager",
55
"keywords": [
66
"BEdita",
@@ -29,7 +29,7 @@
2929
"@trevoreyre/autocomplete-vue": "^2.4.1",
3030
"abortcontroller-polyfill": "^1.7.6",
3131
"autosize": "^5.0.1",
32-
"axios": "^1.7.9",
32+
"axios": "^1.8.2",
3333
"chart.js": "^4.4.7",
3434
"codemirror": "^5.63.3",
3535
"deepmerge": "^4.3.0",

resources/js/app/components/placeholder-list/placeholder-list.vue

+56-13
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,54 @@
1111
v-for="item in items"
1212
:key="itemKey(item)"
1313
>
14-
<app-icon v-if="item.obj?.type === 'audio'" icon="carbon:document-audio" height="24" />
15-
<app-icon v-if="item.obj?.type === 'documents'" icon="carbon:document" height="24" />
16-
<app-icon v-if="item.obj?.type === 'events'" icon="carbon:event" height="24" />
17-
<app-icon v-if="item.obj?.type === 'files'" icon="carbon:document-blank" height="24" />
18-
<app-icon v-if="item.obj?.type === 'images'" icon="carbon:image" height="24" />
19-
<app-icon v-if="item.obj?.type === 'links'" icon="carbon:link" height="24" />
20-
<app-icon v-if="item.obj?.type === 'locations'" icon="carbon:location" height="24" />
21-
<app-icon v-if="item.obj?.type === 'news'" icon="carbon:calendar" height="24" />
22-
<app-icon v-if="item.obj?.type === 'profiles'" icon="carbon:person" height="24" />
23-
<app-icon v-if="item.obj?.type === 'publications'" icon="carbon:wikis" height="24" />
24-
<app-icon v-if="item.obj?.type === 'videos'" icon="carbon:video" height="24" />
14+
<div class="placeholder-item-name">
15+
<app-icon icon="carbon:document-audio"
16+
height="24"
17+
v-if="item.obj?.type === 'audio'"
18+
/>
19+
<app-icon icon="carbon:document"
20+
height="24"
21+
v-if="item.obj?.type === 'documents'"
22+
/>
23+
<app-icon icon="carbon:event"
24+
height="24"
25+
v-if="item.obj?.type === 'events'"
26+
/>
27+
<app-icon icon="carbon:document-blank"
28+
height="24"
29+
v-if="item.obj?.type === 'files'"
30+
/>
31+
<app-icon icon="carbon:image"
32+
height="24"
33+
v-if="item.obj?.type === 'images'"
34+
/>
35+
<app-icon icon="carbon:link"
36+
height="24"
37+
v-if="item.obj?.type === 'links'"
38+
/>
39+
<app-icon icon="carbon:location"
40+
height="24"
41+
v-if="item.obj?.type === 'locations'"
42+
/>
43+
<app-icon icon="carbon:calendar"
44+
height="24"
45+
v-if="item.obj?.type === 'news'"
46+
/>
47+
<app-icon icon="carbon:person"
48+
height="24"
49+
v-if="item.obj?.type === 'profiles'"
50+
/>
51+
<app-icon icon="carbon:wikis"
52+
height="24"
53+
v-if="item.obj?.type === 'publications'"
54+
/>
55+
<app-icon icon="carbon:video"
56+
height="24"
57+
v-if="item.obj?.type === 'videos'"
58+
/>
2559

26-
<span>{{ item.obj?.title }}</span>
60+
<span>{{ item.obj?.title }}</span>
61+
</div>
2762
<placeholder-params
2863
:id="item.id"
2964
:field="field"
@@ -163,11 +198,19 @@ div.placeholdersList > div.header {
163198
}
164199
div.placeholdersList > div.placeholder-item {
165200
display: grid;
166-
grid-template-columns: 5% 60% 1fr;
201+
grid-template-columns: 35% 60% 1fr;
167202
text-align: left;
168203
align-items: center;
169204
gap: 8px;
205+
padding: 4px 0;
170206
margin: 4px 0;
171207
border-top: dotted 1px #ccc;
172208
}
209+
div.placeholdersList > div.placeholder-item > div.placeholder-item-name {
210+
display: flex;
211+
align-items: start;
212+
align-self: flex-start;
213+
gap: 8px;
214+
margin: 4px 0;
215+
}
173216
</style>

resources/js/app/components/placeholder-list/placeholder-params.vue

+55-12
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,51 @@
11
<template>
22
<div class="placeholderParams">
3-
<div v-for="column in Object.keys(parameters)">
4-
<span>{{ t(column) }}</span>
3+
<div v-for="column in Object.keys(parameters)"
4+
:key="column"
5+
>
6+
<span class="paramName">{{ t(column) }}</span>
57
<template v-if="parameters[column] === 'integer'">
6-
<input type="number" :placeholder="column" v-model="decodedValue[column]" @change="changeParams" />
8+
<input type="number"
9+
:placeholder="column"
10+
v-model="decodedValue[column]"
11+
@change="changeParams"
12+
>
713
</template>
814
<template v-if="parameters[column] === 'string'">
9-
<input type="text" :placeholder="column" v-model="decodedValue[column]" @change="changeParams" />
15+
<input type="text"
16+
:placeholder="column"
17+
v-model="decodedValue[column]"
18+
@change="changeParams"
19+
>
1020
</template>
1121
<template v-if="parameters[column] === 'boolean'">
12-
<input type="checkbox" v-model="decodedValue[column]" @click="changeParams" />
22+
<input type="checkbox"
23+
v-model="decodedValue[column]"
24+
@change="changeParams"
25+
>
26+
</template>
27+
<template v-if="parameters[column] === 'richtext'">
28+
<field-textarea
29+
:id="`${column}-${Math.random().toString(36)}`"
30+
:name="column"
31+
:field="column"
32+
:value="decodedValue[column]"
33+
@change="(value) => changeRichText(value, column)"
34+
/>
1335
</template>
1436
<template v-if="typeof parameters[column] === 'object' ">
15-
<select v-model="decodedValue[column]" @change="changeParams">
16-
<option v-for="option in parameters[column]" :value="option">{{ t(option) }}</option>
17-
</select>
37+
<div>
38+
<select v-model="decodedValue[column]"
39+
@change="changeParams"
40+
>
41+
<option v-for="option in parameters[column]"
42+
:key="option"
43+
:value="option"
44+
>
45+
{{ t(option) }}
46+
</option>
47+
</select>
48+
</div>
1849
</template>
1950
</div>
2051
</div>
@@ -82,6 +113,14 @@ export default {
82113
});
83114
this.oldValue = this.newValue;
84115
},
116+
changeParamsBoolean(value, column) {
117+
this.decodedValue[column] = value;
118+
this.changeParams();
119+
},
120+
changeRichText(value, column) {
121+
this.decodedValue[column] = value;
122+
this.changeParams();
123+
},
85124
decoded(item) {
86125
return atob(item);
87126
},
@@ -90,11 +129,15 @@ export default {
90129
</script>
91130
<style>
92131
div.placeholderParams {
93-
display: grid;
94-
grid-template-columns: 1fr 1fr 1fr;
95-
text-align: center;
96-
align-items: center;
132+
display: flex;
133+
flex-direction: column;
97134
gap: 8px;
98135
margin: 4px 0;
99136
}
137+
138+
.paramName {
139+
display: block;
140+
margin-bottom: 4px;
141+
text-transform: capitalize;
142+
}
100143
</style>

resources/js/app/directives/richeditor.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ export default {
6767
});
6868
},
6969

70-
unbind() {
71-
tinymce.remove();
70+
unbind(element) {
71+
tinymce.remove(element.editor);
7272
},
7373

7474
/**
@@ -82,8 +82,12 @@ export default {
8282
if (binding?.value?.toolbar) {
8383
toolbar = binding.value.toolbar.join(' ');
8484
} else if (binding?.expression) {
85-
let exp = JSON.parse(binding.expression);
86-
toolbar = exp ? exp.join(' ') : toolbar;
85+
try {
86+
const exp = JSON.parse(binding.expression);
87+
toolbar = exp ? exp.join(' ') : toolbar;
88+
} catch (e) {
89+
// do nothing
90+
}
8791
}
8892
if (!binding.modifiers?.placeholders) {
8993
toolbar = toolbar.replace(/\bplaceholders\b/, '');

src/Controller/AppController.php

+7-3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ public function initialize(): void
6868
]);
6969
$this->loadComponent('Schema');
7070
$this->loadComponent('Categories');
71+
72+
/** @var \Authentication\Identity|null $identity */
73+
$identity = $this->Authentication->getIdentity();
74+
if ($identity && $identity->get('tokens')) {
75+
$this->apiClient->setupTokens($identity->get('tokens'));
76+
}
7177
}
7278

7379
/**
@@ -77,9 +83,7 @@ public function beforeFilter(EventInterface $event): ?Response
7783
{
7884
/** @var \Authentication\Identity|null $identity */
7985
$identity = $this->Authentication->getIdentity();
80-
if ($identity && $identity->get('tokens')) {
81-
$this->apiClient->setupTokens($identity->get('tokens'));
82-
} elseif (!in_array(rtrim($this->getRequest()->getPath(), '/'), ['/login'])) {
86+
if (!($identity && $identity->get('tokens')) && !in_array(rtrim($this->getRequest()->getPath(), '/'), ['/login'])) {
8387
$route = $this->loginRedirectRoute();
8488
$this->Flash->error(__('Login required'));
8589

src/Controller/Component/ModulesComponent.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,7 @@ protected function modulesByAccessControl(): void
186186
if (empty($user) || empty($user->getOriginalData())) {
187187
return;
188188
}
189-
190-
$roles = (array)$user->get('roles');
189+
$roles = array_intersect(array_keys($accessControl), (array)$user->get('roles'));
191190
$modules = (array)array_keys($this->modules);
192191
$hidden = [];
193192
$readonly = [];
@@ -449,7 +448,6 @@ public function checkRequestForUpload(array $requestData): bool
449448

450449
/**
451450
* Set current attributes from loaded $object data in `currentAttributes`.
452-
* Load session failure data if available.
453451
*
454452
* @param array $object The object.
455453
* @return void

src/Controller/Component/PropertiesComponent.php

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ class PropertiesComponent extends Component
9797
'lang',
9898
'children_order',
9999
'captions',
100+
'roles',
100101
];
101102

102103
/**

src/Controller/Model/ObjectTypesController.php

+10-14
Original file line numberDiff line numberDiff line change
@@ -182,24 +182,20 @@ protected function tables(array $resource): array
182182
*/
183183
protected function prepareProperties(array $data, string $name): array
184184
{
185-
$inherited = $core = $custom = [];
185+
$map = [
186+
'core' => [],
187+
'inherited' => [],
188+
'custom' => [],
189+
];
186190
foreach ($data as $prop) {
187-
if (!is_numeric($prop['id'])) {
188-
$type = $prop['attributes']['object_type_name'];
189-
if ($type == $name) {
190-
$core[] = $prop;
191-
} else {
192-
$inherited[] = $prop;
193-
}
194-
} else {
195-
$custom[] = $prop;
196-
}
191+
$key = !is_numeric($prop['id']) ? ($prop['attributes']['object_type_name'] === $name ? 'core' : 'prop') : 'custom';
192+
$map[$key][] = $prop;
197193
}
198194

199195
return [
200-
'core' => Hash::sort($core, '{n}.attributes.name'),
201-
'inherited' => Hash::sort($inherited, '{n}.attributes.name'),
202-
'custom' => Hash::sort($custom, '{n}.attributes.name'),
196+
'core' => Hash::sort($map['core'], '{n}.attributes.name'),
197+
'inherited' => Hash::sort($map['inherited'], '{n}.attributes.name'),
198+
'custom' => Hash::sort($map['custom'], '{n}.attributes.name'),
203199
];
204200
}
205201

src/Plugin.php

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
* {@inheritDoc}
2020
*
2121
* Extended with BEdita plugins utilities
22+
*
23+
* @codeCoverageIgnore
2224
*/
2325
class Plugin extends CakePlugin
2426
{

tests/TestCase/ApplicationTest.php

+37
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
use Cake\Routing\Middleware\AssetMiddleware;
3333
use Cake\Routing\Middleware\RoutingMiddleware;
3434
use Cake\TestSuite\TestCase;
35+
use ReflectionProperty;
3536

3637
/**
3738
* \App\Application Test Case
@@ -79,6 +80,42 @@ public function testMiddleware(): void
7980
static::assertInstanceOf(OAuth2Middleware::class, $middleware->current());
8081
}
8182

83+
/**
84+
* Test `csrfMiddleware` method
85+
*
86+
* @return void
87+
* @covers ::csrfMiddleware()
88+
*/
89+
public function testCsrfMiddleware(): void
90+
{
91+
$app = new Application(CONFIG);
92+
$app->bootstrap();
93+
$middleware = new MiddlewareQueue();
94+
$middleware = $app->middleware($middleware);
95+
$middleware->rewind();
96+
$current = $middleware->current();
97+
while (!($current instanceof CsrfProtectionMiddleware)) {
98+
$current = $middleware->current();
99+
$middleware->next();
100+
}
101+
$property = new ReflectionProperty($current, 'skipCheckCallback');
102+
$property->setAccessible(true);
103+
$method = $property->getValue($current);
104+
$actual = $method(
105+
new ServerRequest(
106+
[
107+
'environment' => ['REQUEST_METHOD' => 'POST'],
108+
'params' => ['controller' => 'Login', 'action' => 'login'],
109+
'post' => [
110+
'username' => 'abc',
111+
'password' => 'def',
112+
],
113+
]
114+
)
115+
);
116+
static::assertTrue($actual);
117+
}
118+
82119
/**
83120
* Test `bootstrap` method
84121
*

0 commit comments

Comments
 (0)