diff --git a/CHANGELOG.md b/CHANGELOG.md index ec668fe086..ba79507c8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [Date/time fields] Date/time fields now support the usage without timezone support. - [Icons] Overhauled Icon library and icon dropdown selector in class definition editor. - [System Settings] Removed "Default-Language in Admin-Interface" setting. +- [Security] Add CSP configuration option `frame-ancestors` (default: `self`). #### v1.4.0 - [DataObject] Password data type algorithms other than `password_hash` are deprecated since `pimcore/pimcore:^11.2` and will be removed in `pimcore/pimcore:^12`. diff --git a/composer.json b/composer.json index 9c05284ecb..e78e49beea 100644 --- a/composer.json +++ b/composer.json @@ -14,8 +14,8 @@ "require": { "php": "~8.1.0 || ~8.2.0 || ~8.3.0", "cbschuld/browser.php": "^1.9.6", - "phpoffice/phpspreadsheet": "^1.24 || ^2.1", - "pimcore/pimcore": "~11.3.0", + "phpoffice/phpspreadsheet": "^1.24 || ^2.2", + "pimcore/pimcore": "~11.3.1", "symfony/webpack-encore-bundle": "^1.13.2" }, "require-dev": { @@ -40,9 +40,6 @@ "kernel/Kernel.php" ] }, - "conflict": { - "symfony/string": "<6.0" - }, "extra": { "branch-alias": { "1.x-dev": "1.5.x-dev" diff --git a/public/css/admin.css b/public/css/admin.css index e4aa14403a..56d8b3ab07 100644 --- a/public/css/admin.css +++ b/public/css/admin.css @@ -2376,3 +2376,27 @@ ul.leaflet-draw-actions.leaflet-draw-actions-top.leaflet-draw-actions-bottom li: .pimcore_cb_middle_two_lines .x-form-cb-default { top: -9px } + +.pimcore_reverse-object-relation-warning { + width: inherit; + padding: 0 5px 0 20px; + + white-space: initial; + background:url("/bundles/pimcoreadmin/img/icon/error.png") no-repeat scroll 0 0 transparent; +} + +.pimcore_reverse-object-relation-panel { + overflow: visible !important; +} + +.pimcore_reverse-object-relation-panel > .x-panel-bodyWrap { + overflow: visible !important; +} + +.pimcore_reverse-object-relation-bottom-bar { + overflow: visible !important; +} + +.pimcore_reverse-object-relation-bottom-bar > div { + height: 4.5rem !important; +} diff --git a/public/js/pimcore/document/document.js b/public/js/pimcore/document/document.js index cd09171c5a..26ef981748 100644 --- a/public/js/pimcore/document/document.js +++ b/public/js/pimcore/document/document.js @@ -250,13 +250,13 @@ pimcore.document.document = Class.create(pimcore.element.abstract, { const menuItem = this.toolbarButtons.publish.menu.items.items.find( element => element.text === t('save_draft') ) - menuItem.setHidden(false) + menuItem?.setHidden(false) } if (this.isAllowed("settings")) { const menuItem = this.toolbarButtons.publish.menu.items.items.find( element => element.text === t('save_only_scheduled_tasks') ) - menuItem.setHidden(false) + menuItem?.setHidden(false) } this.toolbarButtons.publish.show(); diff --git a/public/js/pimcore/element/helpers/gridCellEditor.js b/public/js/pimcore/element/helpers/gridCellEditor.js index 65094d0a76..51ef1cfd40 100644 --- a/public/js/pimcore/element/helpers/gridCellEditor.js +++ b/public/js/pimcore/element/helpers/gridCellEditor.js @@ -36,41 +36,43 @@ Ext.define('pimcore.element.helpers.gridCellEditor', { value = Ext.clone(value); - var fieldInfo = Ext.clone(this.config.fieldInfo); - var fieldType = this.config.elementType; + const fieldInfo = Ext.clone(this.config.fieldInfo); + const fieldType = this.config.elementType; //make sure that no relation data is loaded async fieldInfo.layout.optimizedAdminLoading = false; - if(!fieldInfo || !fieldInfo.layout) { + if (!fieldInfo?.layout) { return; } - if(fieldInfo.layout.noteditable) { + if (fieldInfo.layout.noteditable) { pimcore.helpers.showNotification(t('warning'), t('this_element_cannot_be_edited'), 'warning'); return; } this.context = this.editingPlugin.context; - // this.callParent(arguments); - var tagType = fieldInfo.layout.fieldtype; + const tagType = fieldInfo.layout.fieldtype; // translate title if(typeof fieldInfo.layout.title != "undefined") { fieldInfo.layout.title = t(fieldInfo.layout.title); } - + let tag; if (fieldType == "assetmetadata") { - var tag = new pimcore.asset.metadata.tags[tagType](value, fieldInfo.layout); + tag = new pimcore.asset.metadata.tags[tagType](value, fieldInfo.layout); } else { - var tag = new pimcore[fieldType].tags[tagType](value, fieldInfo.layout); + tag = new pimcore[fieldType].tags[tagType](value, fieldInfo.layout); } if(fieldType == 'object') { - var object = Ext.clone(this.context.record); + const object = Ext.clone(this.context.record); tag.setObject(object); + tag.updateContext({ + objectId: object.id + }); } tag.updateContext({ @@ -82,7 +84,7 @@ Ext.define('pimcore.element.helpers.gridCellEditor', { tag.finishSetup(); } - var formPanel = Ext.create('Ext.form.Panel', { + const formPanel = Ext.create('Ext.form.Panel', { xtype: "form", border: false, items: [tag.getLayoutEdit()], @@ -145,10 +147,10 @@ Ext.define('pimcore.element.helpers.gridCellEditor', { }, completeEdit: function(remainVisible) { - var me = this, + const me = this, fieldInfo = me.config.fieldInfo, - startValue = me.startValue, - value; + startValue = me.startValue; + let value; if (fieldInfo.layout.noteditable) { return; diff --git a/public/js/pimcore/element/helpers/gridColumnConfig.js b/public/js/pimcore/element/helpers/gridColumnConfig.js index 42d3b4cf51..40fc56e195 100644 --- a/public/js/pimcore/element/helpers/gridColumnConfig.js +++ b/public/js/pimcore/element/helpers/gridColumnConfig.js @@ -456,7 +456,7 @@ pimcore.element.helpers.gridColumnConfig = { title: title, items: [formPanel], bodyStyle: "background: #fff;", - width: 700, + width: formPanel.items.items[0].width + 25, maxHeight: 650 }); this.filterByRelationWindow.show(); @@ -694,6 +694,12 @@ pimcore.element.helpers.gridColumnConfig = { Ext.Msg.alert(t("error"), t("error_jobs") + ":
" + jobErrors.join("
")); } + // Due to some ExtJS bug, when using a lock, the selection is visually cleared after batch operation + // To avoid confusion and disalignment on what we see from what is actually selected, everything is unselected + if (this.grid.hasOwnProperty('enableLocking') && this.grid.enableLocking){ + this.grid.getSelectionModel().deselectAll(); + } + return; } diff --git a/public/js/pimcore/helpers.js b/public/js/pimcore/helpers.js index 0391379402..c8b3008d45 100644 --- a/public/js/pimcore/helpers.js +++ b/public/js/pimcore/helpers.js @@ -3379,7 +3379,7 @@ pimcore.helpers.treeDragDropValidate = function (node, oldParent, newParent) { pimcore.helpers.isComponentAsChildAllowed = function (parentNode, childNode) { const parentType = parentNode.data.editor.type; const childType = childNode.data.editor.type; - const allowedChildren = pimcore.object.helpers.layout.getRawAllowedTypes(); + const allowedChildren = pimcore.object.helpers.layout.getAllowedTypes(); if (allowedChildren[parentType] && allowedChildren[parentType].includes(childType) || diff --git a/public/js/pimcore/object/folder/search.js b/public/js/pimcore/object/folder/search.js index b259abf9fa..da560b7212 100644 --- a/public/js/pimcore/object/folder/search.js +++ b/public/js/pimcore/object/folder/search.js @@ -458,7 +458,7 @@ pimcore.object.search = Class.create(pimcore.object.helpers.gridTabAbstract, { } menu.add(new Ext.menu.Item({ - hidden: data.data.locked, + hidden: data.data.locked || !data.data.permissions.delete, text: t('delete'), iconCls: "pimcore_icon_delete", handler: function (data) { diff --git a/public/js/pimcore/object/tags/dateRange.js b/public/js/pimcore/object/tags/dateRange.js index 32951eeeab..8039096170 100644 --- a/public/js/pimcore/object/tags/dateRange.js +++ b/public/js/pimcore/object/tags/dateRange.js @@ -82,8 +82,8 @@ pimcore.object.tags.dateRange = Class.create(pimcore.object.tags.abstract, { getLayoutShow: function () { this.component = this.getLayoutEdit(); - this.component.items[0].setReadonly(true); - this.component.items[2].setReadonly(true); + this.component.items.items[0].setReadOnly(true); + this.component.items.items[2].setReadOnly(true); return this.component; }, @@ -98,15 +98,16 @@ pimcore.object.tags.dateRange = Class.create(pimcore.object.tags.abstract, { renderer: function (key, value, metaData, record) { this.applyPermissionStyle(key, value, metaData, record); - if (record.data.inheritedFields && record.data.inheritedFields[key] && record.data.inheritedFields[key].inherited === true) { + if (record.data.inheritedFields?.[key]?.inherited) { metaData.tdCls += ' grid_value_inherited'; } if (value) { const minDate = new Date(intval(value['start_date'] || 0) * 1000); const maxDate = new Date(intval(value['end_date'] || 0) * 1000); + const shortDateFormat = pimcore.globalmanager.get('localeDateTime').getShortDateFormat(); - return `${Ext.Date.format(minDate, pimcore.globalmanager.get('localeDateTime').getShortDateFormat()), Ext.Date.format(maxDate, pimcore.globalmanager.get('localeDateTime').getShortDateFormat())}`; + return `${Ext.Date.format(minDate, shortDateFormat)}, ${Ext.Date.format(maxDate, shortDateFormat)}`; } return ''; diff --git a/public/js/pimcore/object/tags/quantityValue.js b/public/js/pimcore/object/tags/quantityValue.js index 54b5d8c3b4..13c2596609 100644 --- a/public/js/pimcore/object/tags/quantityValue.js +++ b/public/js/pimcore/object/tags/quantityValue.js @@ -82,6 +82,11 @@ pimcore.object.tags.quantityValue = Class.create(pimcore.object.tags.abstract, { }); var updateCompatibleUnitsToolTipContent = function() { + if(pimcore.globalmanager.get("user").isAllowed('quantityValueUnits') !== true) { + compatibleUnitsButton.hide(); + return false; + } + if (this.inputField.value === '' || this.inputField.value === null || !this.unitField.value) { compatibleUnitsButton.hide(); return false; diff --git a/public/js/pimcore/object/tags/reverseObjectRelation.js b/public/js/pimcore/object/tags/reverseObjectRelation.js index af757a0eeb..82c66cd6d3 100644 --- a/public/js/pimcore/object/tags/reverseObjectRelation.js +++ b/public/js/pimcore/object/tags/reverseObjectRelation.js @@ -112,10 +112,11 @@ pimcore.object.tags.reverseObjectRelation = Class.create(pimcore.object.tags.man let columns = this.getVisibleColumns(); - this.component = new Ext.grid.GridPanel({ + this.component = new Ext.grid.GridPanel({ store: this.store, border: true, style: "margin-bottom: 10px", + cls: "pimcore_reverse-object-relation-panel", selModel: Ext.create('Ext.selection.RowModel', {}), columns: { defaults: { @@ -160,17 +161,30 @@ pimcore.object.tags.reverseObjectRelation = Class.create(pimcore.object.tags.man tbar: { items: this.getEditToolbarItems(), ctCls: "pimcore_force_auto_width", - cls: "pimcore_force_auto_width" + cls: "pimcore_force_auto_width", }, bbar: { - items: [{ - xtype: "tbtext", - text: ' ' + t('nonownerobject_warning') + " | " + t('owner_class') - + ':' + t(className) + " " + t('owner_field') + ': ' - + t(this.fieldConfig.ownerFieldName) + '' - }], + items: [ + { + xtype: "tbtext", + text: + '
' + + t("nonownerobject_warning") + + "
" + + t("owner_class") + + ": " + + t(className) + + " " + + t("owner_field") + + ": " + + t(this.fieldConfig.ownerFieldName) + + "
", + height: "fit-content", + }, + ], ctCls: "pimcore_force_auto_width", - cls: "pimcore_force_auto_width" + cls: "pimcore_force_auto_width pimcore_reverse-object-relation-bottom-bar", + height: "4.5rem", }, autoHeight: autoHeight, bodyCssClass: "pimcore_object_tag_objects", @@ -179,12 +193,12 @@ pimcore.object.tags.reverseObjectRelation = Class.create(pimcore.object.tags.man listeners: { afterrender: function (gridview) { this.requestNicePathData(this.store.data); - }.bind(this) - } + }.bind(this), + }, }, listeners: { - rowdblclick: this.gridRowDblClickHandler - } + rowdblclick: this.gridRowDblClickHandler, + }, }); this.component.on("rowcontextmenu", this.onRowContextmenu); diff --git a/public/js/pimcore/object/tags/rgbaColor.js b/public/js/pimcore/object/tags/rgbaColor.js index 5a74c80a97..349dcd560d 100644 --- a/public/js/pimcore/object/tags/rgbaColor.js +++ b/public/js/pimcore/object/tags/rgbaColor.js @@ -20,7 +20,6 @@ pimcore.object.tags.rgbaColor = Class.create(pimcore.object.tags.abstract, { type: "rgbaColor", initialize: function (data, fieldConfig) { - this.data = null; if (data) { @@ -31,21 +30,22 @@ pimcore.object.tags.rgbaColor = Class.create(pimcore.object.tags.abstract, { }, getGridColumnConfig: function (field) { - return { - text: t(field.label), width: 120, sortable: false, dataIndex: field.key, sortable: true, + text: t(field.label), + width: 120, + dataIndex: field.key, + sortable: true, getEditor: this.getWindowCellEditor.bind(this, field), renderer: function (key, value, metaData, record) { this.applyPermissionStyle(key, value, metaData, record); - if (record.data.inheritedFields && record.data.inheritedFields[key] && record.data.inheritedFields[key].inherited == true) { + if (record.data.inheritedFields?.[key]?.inherited) { metaData.tdCls += " grid_value_inherited"; } if (value) { - var result = '
' + return '
' + '
' + value + '
'; - return result; } }.bind(this, field.key) @@ -71,28 +71,23 @@ pimcore.object.tags.rgbaColor = Class.create(pimcore.object.tags.abstract, { }, getLayoutEdit: function () { - - var labelWidth = 100; - var width = this.fieldConfig.width ? this.fieldConfig.width : 400; - if (this.fieldConfig.labelWidth) { - labelWidth = this.fieldConfig.labelWidth; + const labelWidth = this.fieldConfig.labelWidth ? this.fieldConfig.labelWidth : 100; + let width = this.fieldConfig.width ? this.fieldConfig.width : 400; + if (!this.fieldConfig.labelAlign || 'left' === this.fieldConfig.labelAlign) { + width = this.sumWidths(width, labelWidth); } - width = this.sumWidths(width, labelWidth); - - this.selector = new Ext.ux.colorpick.Selector( - { - showPreviousColor: true, - hidden: true, - bind: { - value: '{color}', - visible: '{full}' - } + + this.selector = new Ext.ux.colorpick.Selector({ + showPreviousColor: true, + hidden: true, + bind: { + value: '{color}', + visible: '{full}' } - ); + }); - var colorConfig = { - fieldLabel: this.fieldConfig.title, - labelWidth: labelWidth, + const colorConfig = { + flex: 1, format: '#hex8', isNull: !this.data, hidden: true, @@ -103,31 +98,45 @@ pimcore.object.tags.rgbaColor = Class.create(pimcore.object.tags.abstract, { colorConfig["value"] = this.data; } - this.colorField = Ext.create('pimcore.colorpick.Field', + this.colorField = Ext.create( + 'pimcore.colorpick.Field', colorConfig ); - var panel = new Ext.panel.Panel({ + const compositeCfg = { viewModel: { data: { - color: this.data ? this.data : "FFFFFFFF" + color: this.data ? this.data : 'FFFFFFFF' } }, + fieldLabel: this.fieldConfig.title, + labelWidth: labelWidth, layout: 'hbox', width: width, - componentCls: this.getWrapperClassNames(), - items: [this.colorField, this.selector, + items: [ + this.colorField, + this.selector, { - xtype: "button", - iconCls: "pimcore_icon_delete", - style: "margin-left: 5px", - handler: this.empty.bind(this), - }], - style: "padding-bottom: 10px;" - }); + xtype: 'button', + iconCls: 'pimcore_icon_delete', + style: 'margin-left: 5px', + handler: this.empty.bind(this), + } + ], + componentCls: this.getWrapperClassNames(), + border: false, + style: { + padding: 0 + } + }; + + if (this.fieldConfig.labelAlign) { + compositeCfg.labelAlign = this.fieldConfig.labelAlign; + } this.colorField.setVisible(true); - this.component = panel; + this.component = Ext.create('Ext.form.FieldContainer', compositeCfg); + return this.component; }, @@ -137,7 +146,6 @@ pimcore.object.tags.rgbaColor = Class.create(pimcore.object.tags.abstract, { }, getLayoutShow: function () { - this.component = this.getLayoutEdit(); this.component.disable(); @@ -145,13 +153,13 @@ pimcore.object.tags.rgbaColor = Class.create(pimcore.object.tags.abstract, { }, getValue: function () { - var viewModel = this.component.getViewModel(); - var isNull = this.colorField.getIsNull(); + const viewModel = this.component.getViewModel(); + const isNull = this.colorField.getIsNull(); if (isNull) { return null; } - var value = viewModel.get("color"); - return value; + + return viewModel.get("color"); }, getName: function () { @@ -159,8 +167,6 @@ pimcore.object.tags.rgbaColor = Class.create(pimcore.object.tags.abstract, { }, isDirty: function () { - var dirty = this.getValue() != this.data - - return dirty; + return this.getValue() != this.data; } }); diff --git a/src/Controller/Admin/Asset/AssetController.php b/src/Controller/Admin/Asset/AssetController.php index b9a7300276..277cba2ab2 100644 --- a/src/Controller/Admin/Asset/AssetController.php +++ b/src/Controller/Admin/Asset/AssetController.php @@ -1232,7 +1232,7 @@ public function getImageThumbnailAction(Request $request): BinaryFileResponse|Js fpassthru($stream); }, 200, [ 'Content-Type' => $thumbnail->getMimeType(), - 'Access-Control-Allow-Origin', '*', + 'Access-Control-Allow-Origin' => '*', ]); $this->addThumbnailCacheHeaders($response); @@ -2330,6 +2330,12 @@ public function gridProxyAction(Request $request, EventDispatcherInterface $even } if ($dirty) { + $metadataEvent = new GenericEvent($this, [ + 'id' => $asset->getId(), + 'metadata' => $metadata, + ]); + $eventDispatcher->dispatch($metadataEvent, AdminEvents::ASSET_METADATA_PRE_SET); + // $metadata = Asset\Service::minimizeMetadata($metadata, "grid"); $asset->setMetadataRaw($metadata); $asset->save(); diff --git a/src/Controller/Admin/Asset/AssetHelperController.php b/src/Controller/Admin/Asset/AssetHelperController.php index 07e3d2e360..099fa83b3d 100644 --- a/src/Controller/Admin/Asset/AssetHelperController.php +++ b/src/Controller/Admin/Asset/AssetHelperController.php @@ -604,7 +604,7 @@ protected function updateGridConfigFavourites(?GridConfig $gridConfig, array $me $sharedUserIds = $metadata['sharedUserIds']; if ($sharedUserIds) { - $sharedUsers = explode(',', $sharedUserIds); + $sharedUsers = array_map('intval', explode(',', $sharedUserIds)); } } @@ -620,7 +620,7 @@ protected function updateGridConfigFavourites(?GridConfig $gridConfig, array $me foreach ($sharedUsers as $id) { // Check if the user has already a favourite $favourite = GridConfigFavourite::getByOwnerAndClassAndObjectId( - (int) $id, + $id, $gridConfig->getClassId(), 0, $gridConfig->getSearchType() @@ -636,7 +636,7 @@ protected function updateGridConfigFavourites(?GridConfig $gridConfig, array $me } // Check if the user is the owner. If that is the case we do not update the favourite - if ((int) $favouriteGridConfig->getOwnerId() === (int) $id) { + if ($favouriteGridConfig->getOwnerId() === $id) { continue; } } @@ -1054,6 +1054,12 @@ public function batchAction(Request $request, EventDispatcherInterface $eventDis try { if ($dirty) { + $metadataEvent = new GenericEvent($this, [ + 'id' => $asset->getId(), + 'metadata' => $metadata, + ]); + $eventDispatcher->dispatch($metadataEvent, AdminEvents::ASSET_METADATA_PRE_SET); + // $metadata = Asset\Service::minimizeMetadata($metadata, "grid"); $asset->setMetadataRaw($metadata); $asset->save(); diff --git a/src/Controller/Admin/DataObject/DataObjectActionsTrait.php b/src/Controller/Admin/DataObject/DataObjectActionsTrait.php index ef7e2e7d2d..40c59c0fd2 100644 --- a/src/Controller/Admin/DataObject/DataObjectActionsTrait.php +++ b/src/Controller/Admin/DataObject/DataObjectActionsTrait.php @@ -229,7 +229,6 @@ private function prepareObjectData( $fieldGetter = 'get' . ucfirst($brickField); $brickGetter = 'get' . ucfirst($brickType); - $valueSetter = 'set' . ucfirst($brickKey); $brick = $object->$fieldGetter()->$brickGetter(); if (empty($brick)) { @@ -257,7 +256,7 @@ private function prepareObjectData( $localizedFields = $brick->getLocalizedfields(); $localizedFields->setLocalizedValue($brickKey, $value); } else { - $brick->$valueSetter($value); + $brick->setObjectVar($brickKey, $value); } } else { if ($languagePermissions) { diff --git a/src/Controller/Admin/DataObject/DataObjectController.php b/src/Controller/Admin/DataObject/DataObjectController.php index 78e1daab9e..159ff190fa 100644 --- a/src/Controller/Admin/DataObject/DataObjectController.php +++ b/src/Controller/Admin/DataObject/DataObjectController.php @@ -410,7 +410,7 @@ static function (Task $task) { try { $this->getDataForObject($object, $objectFromVersion); - } catch(\Throwable $e) { + } catch (\Throwable $e) { $object = $objectFromDatabase; $this->getDataForObject($object, false); } @@ -1352,7 +1352,7 @@ public function saveAction(Request $request): JsonResponse if ($request->get('data')) { try { $this->applyChanges($object, $this->decodeJson($request->get('data'))); - } catch(\Throwable $e) { + } catch (\Throwable $e) { $this->applyChanges($objectFromDatabase, $this->decodeJson($request->get('data'))); } } diff --git a/src/Controller/Admin/DataObject/DataObjectHelperController.php b/src/Controller/Admin/DataObject/DataObjectHelperController.php index bdecb29d3b..02ea68322d 100644 --- a/src/Controller/Admin/DataObject/DataObjectHelperController.php +++ b/src/Controller/Admin/DataObject/DataObjectHelperController.php @@ -317,7 +317,7 @@ public function doGetGridColumnConfig(Request $request, Config $config, bool $is $setAsFavourite = $savedGridConfig->isSetAsFavourite(); $saveFilters = $savedGridConfig->isSaveFilters(); - foreach($gridConfig['columns'] as &$column) { + foreach ($gridConfig['columns'] as &$column) { if (array_key_exists('isOperator', $column) && $column['isOperator']) { $colAttributes = &$column['fieldConfig']['attributes']; SecurityHelper::convertHtmlSpecialCharsArrayKeys($colAttributes, ['label', 'attribute', 'param1']); @@ -360,12 +360,9 @@ public function doGetGridColumnConfig(Request $request, Config $config, bool $is 'key' => $key, 'type' => 'system', 'label' => $key, - 'locked' => $sc['locked'] ?? null, 'position' => $sc['position'], ]; - if (isset($sc['width'])) { - $colConfig['width'] = $sc['width']; - } + $this->injectCustomLayoutValues($colConfig, $sc); $availableFields[] = $colConfig; } else { $keyParts = explode('~', $key); @@ -387,9 +384,7 @@ public function doGetGridColumnConfig(Request $request, Config $config, bool $is if ($fieldConfig) { $fieldConfig['key'] = $key; $fieldConfig['label'] = '#' . $keyFieldDef->getTitle(); - if (isset($sc['locked'])) { - $fieldConfig['locked'] = $sc['locked']; - } + $fieldConfig = $this->injectCustomLayoutValues($fieldConfig, $sc); $availableFields[] = $fieldConfig; } } @@ -427,12 +422,7 @@ public function doGetGridColumnConfig(Request $request, Config $config, bool $is if ($fd !== null) { $fieldConfig = $this->getFieldGridConfig($fd, $gridType, (string)$sc['position'], true, $keyPrefix, $class, $objectId); if (!empty($fieldConfig)) { - if (isset($sc['width'])) { - $fieldConfig['width'] = $sc['width']; - } - if (isset($sc['locked'])) { - $fieldConfig['locked'] = $sc['locked']; - } + $fieldConfig = $this->injectCustomLayoutValues($fieldConfig, $sc); $availableFields[] = $fieldConfig; } } @@ -457,12 +447,7 @@ public function doGetGridColumnConfig(Request $request, Config $config, bool $is if (!empty($fd)) { $fieldConfig = $this->getFieldGridConfig($fd, $gridType, (string)$sc['position'], true, null, $class, $objectId); if (!empty($fieldConfig)) { - if (isset($sc['width'])) { - $fieldConfig['width'] = $sc['width']; - } - if (isset($sc['locked'])) { - $fieldConfig['locked'] = $sc['locked']; - } + $fieldConfig = $this->injectCustomLayoutValues($fieldConfig, $sc); $availableFields[] = $fieldConfig; } } @@ -530,6 +515,26 @@ public function doGetGridColumnConfig(Request $request, Config $config, bool $is ]; } + private function injectCustomLayoutValues(array $fieldConfig, array $savedColumn): array + { + $keys = ['width', 'locked']; + foreach ($keys as $key) { + if (isset($savedColumn[$key])) { + $fieldConfig[$key] = $savedColumn[$key]; + } + } + + $fieldConfigKeys = ['noteditable']; + foreach ($fieldConfigKeys as $fieldConfigKey) { + if (isset($savedColumn['fieldConfig']['layout'][$fieldConfigKey])) { + $setter = 'set' . ucfirst($fieldConfigKey); + $fieldConfig['layout']->$setter($savedColumn['fieldConfig']['layout'][$fieldConfigKey]); + } + } + + return $fieldConfig; + } + /** * @param DataObject\ClassDefinition\Data[]|null $fields */ @@ -975,7 +980,7 @@ protected function updateGridConfigFavourites(?GridConfig $gridConfig, array $me $sharedUserIds = $metadata['sharedUserIds']; if ($sharedUserIds) { - $sharedUsers = explode(',', $sharedUserIds); + $sharedUsers = array_map('intval', explode(',', $sharedUserIds)); } } @@ -991,7 +996,7 @@ protected function updateGridConfigFavourites(?GridConfig $gridConfig, array $me foreach ($sharedUsers as $id) { $global = true; $favourite = GridConfigFavourite::getByOwnerAndClassAndObjectId( - (int) $id, + $id, $gridConfig->getClassId(), $objectId, $gridConfig->getSearchType() @@ -1008,7 +1013,7 @@ protected function updateGridConfigFavourites(?GridConfig $gridConfig, array $me } // Check if the user is the owner. If that is the case we do not update the favourite - if ((int) $favouriteGridConfig->getOwnerId() === (int) $id) { + if ($favouriteGridConfig->getOwnerId() === $id) { continue; } } @@ -1016,7 +1021,7 @@ protected function updateGridConfigFavourites(?GridConfig $gridConfig, array $me // Check if the user has already a global favourite then we do not save the favourite as global $favourite = GridConfigFavourite::getByOwnerAndClassAndObjectId( - (int) $id, + $id, $gridConfig->getClassId(), 0, $gridConfig->getSearchType() @@ -1032,7 +1037,7 @@ protected function updateGridConfigFavourites(?GridConfig $gridConfig, array $me } // Check if the user is the owner. If that is the case we do not update the global favourite - if ($favouriteGridConfig->getOwnerId() === (int) $id) { + if ($favouriteGridConfig->getOwnerId() === $id) { $global = false; } } @@ -1179,7 +1184,7 @@ public function getExportJobsAction(Request $request, GridHelperService $gridHel //prepare fields $fieldnames = []; $fields = json_decode($allParams['fields'][0], true); - foreach($fields as $field) { + foreach ($fields as $field) { $fieldnames[] = $field['key']; } $allParams['fields'] = $fieldnames; diff --git a/src/Controller/Admin/ElementController.php b/src/Controller/Admin/ElementController.php index 1bc30de37b..9d02a77bde 100644 --- a/src/Controller/Admin/ElementController.php +++ b/src/Controller/Admin/ElementController.php @@ -703,7 +703,7 @@ public function getRequiresDependenciesAction(Request $request): JsonResponse 'requires' => [], // Initialize 'requires' as an empty array ]; - if(count($elements) > 0) { + if (count($elements) > 0) { $result = Model\Element\Service::getFilterRequiresForFrontend($elements); $result['total'] = count($result['requires']); @@ -765,7 +765,7 @@ public function getRequiredByDependenciesAction(Request $request): JsonResponse 'requiredBy' => [], // Initialize 'requiredBy' as an empty array ]; - if(count($elements) > 0) { + if (count($elements) > 0) { $result = Model\Element\Service::getFilterRequiredByPathForFrontend($elements); $result['total'] = count($result['requiredBy']); diff --git a/src/Controller/Admin/MiscController.php b/src/Controller/Admin/MiscController.php index 3f4762cf5b..87e6bf0561 100644 --- a/src/Controller/Admin/MiscController.php +++ b/src/Controller/Admin/MiscController.php @@ -129,7 +129,7 @@ public function jsonTranslationsSystemAction(Request $request, TranslatorInterfa public function scriptProxyAction(Request $request): Response { $storageFile = $request->get('storageFile'); - if(!$storageFile) { + if (!$storageFile) { throw new \InvalidArgumentException('The parameter storageFile is required'); } diff --git a/src/Controller/Admin/TranslationController.php b/src/Controller/Admin/TranslationController.php index facd96ec9c..d3f6af8783 100644 --- a/src/Controller/Admin/TranslationController.php +++ b/src/Controller/Admin/TranslationController.php @@ -634,10 +634,10 @@ protected function getGridFilterCondition(Request $request, string $tableName, b ]; } - if(!empty($conditionFilters)) { + if (!empty($conditionFilters)) { $conditions = []; $params = []; - foreach($conditionFilters as $conditionFilter) { + foreach ($conditionFilters as $conditionFilter) { $conditions[] = $conditionFilter['condition']; $params[$conditionFilter['field']] = $conditionFilter['value']; } diff --git a/src/Helper/GridHelperService.php b/src/Helper/GridHelperService.php index a5256152fb..e6deaffb56 100644 --- a/src/Helper/GridHelperService.php +++ b/src/Helper/GridHelperService.php @@ -699,7 +699,7 @@ public function prepareListingForGrid(array $requestParams, string $requestedLan if (isset($requestParams['filter_by_object_type'])) { if ($requestParams['filter_by_object_type'] === 'only_objects') { $list->setObjectTypes([DataObject::OBJECT_TYPE_OBJECT]); - } elseif($requestParams['filter_by_object_type'] === 'only_variant_objects') { + } elseif ($requestParams['filter_by_object_type'] === 'only_variant_objects') { $list->setObjectTypes([DataObject::OBJECT_TYPE_VARIANT]); } } diff --git a/src/Security/ContentSecurityPolicyHandler.php b/src/Security/ContentSecurityPolicyHandler.php index 3a93ab2c84..225bc4bef2 100644 --- a/src/Security/ContentSecurityPolicyHandler.php +++ b/src/Security/ContentSecurityPolicyHandler.php @@ -30,6 +30,8 @@ class ContentSecurityPolicyHandler implements LoggerAwareInterface private ?string $nonce = null; + private const SELF = "'self'"; + public const DEFAULT_OPT = 'default-src'; public const IMG_OPT = 'img-src'; @@ -46,6 +48,8 @@ class ContentSecurityPolicyHandler implements LoggerAwareInterface public const FRAME_OPT = 'frame-src'; + public const FRAME_ANCHESTORS = 'frame-ancestors'; + public const WORKER_OPT = 'worker-src'; private array $allowedUrls = [ @@ -74,15 +78,16 @@ public function __construct(protected Config $config, protected array $cspHeader public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ - self::DEFAULT_OPT => "'self'", + self::DEFAULT_OPT => self::SELF, self::IMG_OPT => '* data: blob:', - self::MEDIA_OPT => "'self' data:", - self::SCRIPT_OPT => "'self' 'nonce-" . $this->getNonce() . "' 'unsafe-inline' 'unsafe-eval'", - self::STYLE_OPT => "'self' 'unsafe-inline'", - self::FRAME_OPT => "'self' data:", - self::CONNECT_OPT => "'self' blob:", - self::FONT_OPT => "'self'", - self::WORKER_OPT => "'self' blob:", + self::MEDIA_OPT => self::SELF . ' data:', + self::SCRIPT_OPT => self::SELF . " 'nonce-" . $this->getNonce() . "' 'unsafe-inline' 'unsafe-eval'", + self::STYLE_OPT => self::SELF . " 'unsafe-inline'", + self::FRAME_OPT => self::SELF . ' data:', + self::FRAME_ANCHESTORS => self::SELF, + self::CONNECT_OPT => self::SELF . ' blob:', + self::FONT_OPT => self::SELF, + self::WORKER_OPT => self::SELF . ' blob:', ]); } diff --git a/src/Service/PreviewGenerator.php b/src/Service/PreviewGenerator.php index 688b310767..7899277c31 100644 --- a/src/Service/PreviewGenerator.php +++ b/src/Service/PreviewGenerator.php @@ -115,7 +115,7 @@ protected function getSitePreviewConfig(Concrete $object): array $domains = $site->getDomains(); array_unshift($domains, $site->getMainDomain()); - if(is_null($preSelectedSite) && in_array(Tool::getHostname(), $domains)) { + if (is_null($preSelectedSite) && in_array(Tool::getHostname(), $domains)) { $preSelectedSite = $sitesOptions[$label]; } } diff --git a/src/System/AdminConfig.php b/src/System/AdminConfig.php index 65b98748d5..45f03887f2 100644 --- a/src/System/AdminConfig.php +++ b/src/System/AdminConfig.php @@ -62,7 +62,7 @@ public static function get(): array // If the read target is settings-store and no data is found there, // load the data from the container config - if(!$data && $loadType === $repository::LOCATION_SETTINGS_STORE) { + if (!$data && $loadType === $repository::LOCATION_SETTINGS_STORE) { $containerConfig = \Pimcore::getContainer()->getParameter('pimcore_admin.config'); $data[self::BRANDING] = $containerConfig[self::BRANDING]; $data[self::ASSETS] = $containerConfig[self::ASSETS];