SuiteCRM 8.6.1 Release

This commit is contained in:
Jack Anderson 2024-05-28 10:34:28 +01:00
parent 1a39227980
commit f483bec4cf
25 changed files with 1713 additions and 1498 deletions

View file

@ -2,7 +2,7 @@
<img width="180px" height="41px" src="https://suitecrm.com/wp-content/uploads/2017/12/logo.png" align="right" />
</a>
# SuiteCRM 8.6.0
# SuiteCRM 8.6.1
[![LICENSE](https://img.shields.io/github/license/suitecrm/suitecrm.svg)](https://github.com/salesagility/suitecrm/blob/hotfix/LICENSE.txt)
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/salesagility/SuiteCRM-Core/issues)

View file

@ -1 +1 @@
8.6.0
8.6.1

View file

@ -87,7 +87,6 @@
"tecnickcom/tcpdf": "^6.4",
"tedivm/jshrink": "^1.3",
"tinymce/tinymce": "^5.10",
"tuupola/slim-jwt-auth": "^2.0",
"vlucas/phpdotenv": "^3.5",
"voku/anti-xss": "^4.1",
"webonyx/graphql-php": "^0.13.8",

140
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "e576320852b29ba5bbaeb161fdb3904f",
"content-hash": "0013c270369ae4573daa9e6c29448bc5",
"packages": [
{
"name": "api-platform/core",
@ -1955,25 +1955,31 @@
},
{
"name": "firebase/php-jwt",
"version": "v5.5.1",
"version": "v6.10.0",
"source": {
"type": "git",
"url": "https://github.com/firebase/php-jwt.git",
"reference": "83b609028194aa042ea33b5af2d41a7427de80e6"
"reference": "a49db6f0a5033aef5143295342f1c95521b075ff"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/83b609028194aa042ea33b5af2d41a7427de80e6",
"reference": "83b609028194aa042ea33b5af2d41a7427de80e6",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/a49db6f0a5033aef5143295342f1c95521b075ff",
"reference": "a49db6f0a5033aef5143295342f1c95521b075ff",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
"php": "^7.4||^8.0"
},
"require-dev": {
"phpunit/phpunit": ">=4.8 <=9"
"guzzlehttp/guzzle": "^6.5||^7.4",
"phpspec/prophecy-phpunit": "^2.0",
"phpunit/phpunit": "^9.5",
"psr/cache": "^1.0||^2.0",
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0"
},
"suggest": {
"ext-sodium": "Support EdDSA (Ed25519) signatures",
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
},
"type": "library",
@ -2004,7 +2010,11 @@
"jwt",
"php"
],
"time": "2021-11-08T20:18:51+00:00"
"support": {
"issues": "https://github.com/firebase/php-jwt/issues",
"source": "https://github.com/firebase/php-jwt/tree/v6.10.0"
},
"time": "2023-12-01T16:26:39+00:00"
},
{
"name": "friendsofphp/proxy-manager-lts",
@ -3199,16 +3209,16 @@
},
{
"name": "league/oauth2-server",
"version": "8.4.1",
"version": "8.4.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/oauth2-server.git",
"reference": "eed31d86d8cc8e6e9c9f58fbb2113494f8b41e24"
"reference": "007dc5f6c0151a73b133fec36c9686cc956209d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/eed31d86d8cc8e6e9c9f58fbb2113494f8b41e24",
"reference": "eed31d86d8cc8e6e9c9f58fbb2113494f8b41e24",
"url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/007dc5f6c0151a73b133fec36c9686cc956209d3",
"reference": "007dc5f6c0151a73b133fec36c9686cc956209d3",
"shasum": ""
},
"require": {
@ -3273,13 +3283,17 @@
"secure",
"server"
],
"support": {
"issues": "https://github.com/thephpleague/oauth2-server/issues",
"source": "https://github.com/thephpleague/oauth2-server/tree/8.4.2"
},
"funding": [
{
"url": "https://github.com/sephster",
"type": "github"
}
],
"time": "2023-03-22T11:47:53+00:00"
"time": "2023-08-02T22:54:39+00:00"
},
{
"name": "league/uri",
@ -4243,16 +4257,16 @@
},
{
"name": "phpseclib/phpseclib",
"version": "3.0.19",
"version": "3.0.37",
"source": {
"type": "git",
"url": "https://github.com/phpseclib/phpseclib.git",
"reference": "cc181005cf548bfd8a4896383bb825d859259f95"
"reference": "cfa2013d0f68c062055180dd4328cc8b9d1f30b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/cc181005cf548bfd8a4896383bb825d859259f95",
"reference": "cc181005cf548bfd8a4896383bb825d859259f95",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/cfa2013d0f68c062055180dd4328cc8b9d1f30b8",
"reference": "cfa2013d0f68c062055180dd4328cc8b9d1f30b8",
"shasum": ""
},
"require": {
@ -4331,6 +4345,10 @@
"x.509",
"x509"
],
"support": {
"issues": "https://github.com/phpseclib/phpseclib/issues",
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.37"
},
"funding": [
{
"url": "https://github.com/terrafrost",
@ -4345,7 +4363,7 @@
"type": "tidelift"
}
],
"time": "2023-03-05T17:13:09+00:00"
"time": "2024-03-03T02:14:58+00:00"
},
{
"name": "pimple/pimple",
@ -9802,20 +9820,20 @@
},
{
"name": "tecnickcom/tcpdf",
"version": "6.6.2",
"version": "6.7.5",
"source": {
"type": "git",
"url": "https://github.com/tecnickcom/TCPDF.git",
"reference": "e3cffc9bcbc76e89e167e9eb0bbda0cab7518459"
"reference": "951eabf0338ec2522bd0d5d9c79b08a3a3d36b36"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/e3cffc9bcbc76e89e167e9eb0bbda0cab7518459",
"reference": "e3cffc9bcbc76e89e167e9eb0bbda0cab7518459",
"url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/951eabf0338ec2522bd0d5d9c79b08a3a3d36b36",
"reference": "951eabf0338ec2522bd0d5d9c79b08a3a3d36b36",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
"php": ">=5.5.0"
},
"type": "library",
"autoload": {
@ -9840,7 +9858,7 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-only"
"LGPL-3.0-or-later"
],
"authors": [
{
@ -9860,13 +9878,17 @@
"pdf417",
"qrcode"
],
"support": {
"issues": "https://github.com/tecnickcom/TCPDF/issues",
"source": "https://github.com/tecnickcom/TCPDF/tree/6.7.5"
},
"funding": [
{
"url": "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&currency_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20tcpdf%20project",
"type": "custom"
}
],
"time": "2022-12-17T10:28:59+00:00"
"time": "2024-04-20T17:25:10+00:00"
},
{
"name": "tedivm/jshrink",
@ -9926,16 +9948,16 @@
},
{
"name": "tinymce/tinymce",
"version": "5.10.7",
"version": "5.10.9",
"source": {
"type": "git",
"url": "https://github.com/tinymce/tinymce-dist.git",
"reference": "f078d8eb7de81f20d34b2ae4326870d20e22d4ff"
"reference": "e5650a256f8941a0593ec0b9d3c435f20f1d4245"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tinymce/tinymce-dist/zipball/f078d8eb7de81f20d34b2ae4326870d20e22d4ff",
"reference": "f078d8eb7de81f20d34b2ae4326870d20e22d4ff",
"url": "https://api.github.com/repos/tinymce/tinymce-dist/zipball/e5650a256f8941a0593ec0b9d3c435f20f1d4245",
"reference": "e5650a256f8941a0593ec0b9d3c435f20f1d4245",
"shasum": ""
},
"type": "component",
@ -9976,62 +9998,10 @@
"tinymce",
"wysiwyg"
],
"time": "2022-12-07T03:50:54+00:00"
},
{
"name": "tuupola/slim-jwt-auth",
"version": "2.4.0",
"source": {
"type": "git",
"url": "https://github.com/tuupola/slim-jwt-auth.git",
"reference": "bca54de41a8207d4d67faf3601a06a96cb7ed48f"
"support": {
"source": "https://github.com/tinymce/tinymce-dist/tree/5.10.9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tuupola/slim-jwt-auth/zipball/bca54de41a8207d4d67faf3601a06a96cb7ed48f",
"reference": "bca54de41a8207d4d67faf3601a06a96cb7ed48f",
"shasum": ""
},
"require": {
"firebase/php-jwt": "^3.0 || ^4.0 || ^5.0",
"php": "^5.5 || ^7.0",
"psr/http-message": "^1.0",
"psr/log": "^1.0"
},
"require-dev": {
"overtrue/phplint": "^0.2.4",
"phpunit/phpunit": "^4.6",
"squizlabs/php_codesniffer": "^2.3",
"zendframework/zend-diactoros": "^1.3"
},
"type": "library",
"autoload": {
"psr-4": {
"Slim\\Middleware\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mika Tuupola",
"email": "tuupola@appelsiini.net",
"homepage": "http://www.appelsiini.net/",
"role": "Developer"
}
],
"description": "PSR-7 JWT Authentication Middleware",
"homepage": "https://github.com/tuupola/slim-jwt-auth",
"keywords": [
"auth",
"json",
"jwt",
"middleware",
"psr-7"
],
"time": "2018-04-03T06:12:18+00:00"
"time": "2023-11-15T00:42:08+00:00"
},
{
"name": "twig/twig",
@ -16320,5 +16290,5 @@
"platform-overrides": {
"php": "7.4.0"
},
"plugin-api-version": "1.1.0"
"plugin-api-version": "2.6.0"
}

View file

@ -1,6 +1,6 @@
{
"name": "common",
"version": "8.6.0",
"version": "8.6.1",
"peerDependencies": {
"@angular/common": "^12.1.0",
"@angular/core": "^12.1.0",

View file

@ -46,6 +46,8 @@ export interface ViewFieldDefinition {
metadata?: FieldMetadata;
logic?: FieldLogicMap;
displayLogic?: FieldLogicMap;
[key: string]: any;
}
export interface Panel {

View file

@ -1,6 +1,6 @@
{
"name": "core",
"version": "8.6.0",
"version": "8.6.1",
"peerDependencies": {
"@angular/common": "^12.1.0",
"@angular/core": "^12.1.0",

View file

@ -43,7 +43,7 @@ import {
import {AsyncValidatorFn, UntypedFormArray, UntypedFormControl, ValidatorFn} from '@angular/forms';
import {LanguageStore} from '../../../store/language/language.store';
import get from 'lodash-es/get';
import {merge} from 'lodash-es';
import {isEmpty, merge} from 'lodash-es';
import {FieldObjectRegistry} from "./field-object-type.registry";
@ -69,7 +69,15 @@ export class FieldBuilder {
*/
public buildField(record: Record, viewField: ViewFieldDefinition, language: LanguageStore = null): Field {
const definition = (viewField && viewField.fieldDefinition) || {} as FieldDefinition;
const module = record?.module ?? '';
let definition = viewField?.fieldDefinition ?? {} as FieldDefinition;
const multiModuleDefinitions = viewField?.multiModuleDefinitions ?? {} as ObjectMap;
const currentModuleDefinitions = multiModuleDefinitions[module] ?? {} as FieldDefinition;
if (!isEmpty(currentModuleDefinitions)){
definition = currentModuleDefinitions;
}
const {value, valueList, valueObject} = this.parseValue(viewField, definition, record);
const {validators, asyncValidators} = this.getSaveValidators(record, viewField);

View file

@ -221,7 +221,7 @@ class InstallHandler extends LegacyHandler
$checkFile = __DIR__ . '/../../../../.curl_check_main_page';
require_once "core/backend/Install/Service/InstallPreChecks.php";
require_once __DIR__ . "/../../../../core/backend/Install/Service/InstallPreChecks.php";
$installChecks = new InstallPreChecks($log);
try {

View file

@ -71,11 +71,16 @@ trait InstallationUtilsTrait
public function getLegacyConfig($legacyDir): ?array
{
$sugarConfigFile = $legacyDir . '/config.php';
$sugarOverrideConfigFile = $legacyDir . '/config_override.php';
if (is_file($sugarConfigFile)) {
$sugar_config = [];
include $sugarConfigFile;
if (is_file($sugarOverrideConfigFile)) {
include $sugarOverrideConfigFile;
}
return $sugar_config;
}

View file

@ -114,15 +114,22 @@ class Kernel extends BaseKernel
$routes->import($confDir . '/{routes}' . self::CONFIG_EXTS, '/', 'glob');
}
/**
* Init bundles and container
* @return void
*/
public function init(): void
{
$this->initializeBundles();
$this->initializeContainer();
}
/**
* @param Request $request
* @return array
*/
public function getLegacyRoute(Request $request): array
{
$this->initializeBundles();
$this->initializeContainer();
if ($this->container->has('legacy.route.handler')) {
return $this->container->get('legacy.route.handler')->getLegacyRoute($request);
}

View file

@ -112,7 +112,7 @@ class LegacyApiRedirectHandler extends LegacyRedirectHandler
return [
'dir' => '',
'file' => 'index.php',
'file' => './index.php',
'access' => true
];
}

View file

@ -28,6 +28,7 @@
namespace App\Routes\Service;
use InvalidArgumentException;
use Symfony\Component\HttpFoundation\Request;
class LegacyRedirectHandler
@ -88,6 +89,10 @@ class LegacyRedirectHandler
$baseUrl = substr($baseUrl, 1);
if (strpos($baseUrl, '../') !== false) {
throw new InvalidArgumentException('invalid path');
}
if (strpos($baseUrl, '.php') === false) {
$baseUrl .= 'index.php';
}

View file

@ -62,8 +62,7 @@ trait FieldDefinitionsInjectorTrait
return $field;
}
$alias = $fieldAliasMapper->map($vardefs[$name]);
$aliasDefs = $vardefs[$alias] ?? $vardefs[$name];
$aliasDefs = $this->getAliasDefinitions($fieldAliasMapper, $vardefs, $name);
$field['fieldDefinition'] = $aliasDefs;
$field['name'] = $aliasDefs['name'] ?? $field['name'];
@ -112,4 +111,20 @@ trait FieldDefinitionsInjectorTrait
return $field;
}
/**
* @param FieldAliasMapper $fieldAliasMapper
* @param array $vardefs
* @param string $name
* @return mixed
*/
protected function getAliasDefinitions(FieldAliasMapper $fieldAliasMapper, array $vardefs, string $name)
{
if (empty($vardefs[$name])) {
return [];
}
$alias = $fieldAliasMapper->map($vardefs[$name]);
return $vardefs[$alias] ?? $vardefs[$name];
}
}

View file

@ -198,9 +198,11 @@ class SubPanelDefinitionHandler extends LegacyHandler implements SubPanelDefinit
}
$columnSubpanel = $subpanel;
$extraModuleVardefs = [];
if (!empty($tab['collection_list'])) {
$columnSubpanel = $subpanel->get_header_panel_def();
$headerModule = $this->moduleNameMapper->toFrontEnd($columnSubpanel->get_module_name());
$extraModuleVardefs = $this->getCollectionListVardefs($tab['collection_list']);
} else {
$headerModule = $this->getHeaderModule($tab);
}
@ -223,7 +225,7 @@ class SubPanelDefinitionHandler extends LegacyHandler implements SubPanelDefinit
$resultingTabs[$key] = $tabs[$key];
$mapColumns = $this->mapColumns($columnSubpanel, $vardefs);
$mapColumns = $this->mapColumns($columnSubpanel, $vardefs, $extraModuleVardefs);
if (!empty($tab['collection_list'])) {
$iconColumn = $this->buildIconColumn($tab['module']);
@ -292,9 +294,9 @@ class SubPanelDefinitionHandler extends LegacyHandler implements SubPanelDefinit
$topButtonDefinitions = $this->getButtonDefinitions($subpanel);
foreach($topButtonDefinitions as $key => $value){
if (stripos($value['widget_class'], 'topfilter')){
if (!$this->getSearchdefs($subpanel) && !$searchDefs['searchdefs']){
foreach ($topButtonDefinitions as $key => $value) {
if (stripos($value['widget_class'], 'topfilter')) {
if (!$this->getSearchdefs($subpanel) && !$searchDefs['searchdefs']) {
unset($topButtonDefinitions[$key]);
break;
}
@ -321,7 +323,7 @@ class SubPanelDefinitionHandler extends LegacyHandler implements SubPanelDefinit
protected function getSearchdefs(aSubPanel $subpanel) {
$searchDefs = $subpanel->_instance_properties['searchdefs'] ?? '';
if (!empty($searchDefs)){
if (!empty($searchDefs)) {
foreach ($searchDefs as &$field) {
$fieldDefinition = [
'name' => $field['name'],
@ -354,7 +356,7 @@ class SubPanelDefinitionHandler extends LegacyHandler implements SubPanelDefinit
* @param array $vardefs
* @return array
*/
protected function mapColumns(aSubPanel $subpanel, array $vardefs): array
protected function mapColumns(aSubPanel $subpanel, array $vardefs, array $extraModuleVardefs): array
{
$panelDefinition = $subpanel->panel_definition ?? [];
$listFields = $panelDefinition['list_fields'] ?? [];
@ -377,7 +379,13 @@ class SubPanelDefinitionHandler extends LegacyHandler implements SubPanelDefinit
continue;
}
$definitions[] = $this->buildColumn($column, $key, $vardefs);
$definition = $this->buildColumn($column, $key, $vardefs);
if (!empty($extraModuleVardefs)) {
$definition = $this->addMultiModuleVardefs($extraModuleVardefs, $key, $definition);
}
$definitions[] = $definition;
}
return $definitions;
@ -597,4 +605,70 @@ class SubPanelDefinitionHandler extends LegacyHandler implements SubPanelDefinit
return $lineActions;
}
/**
* @param $collection_list
* @return array
*/
protected function getCollectionListVardefs($collection_list): array
{
$extraModuleVardefs = [];
if (!is_array($collection_list)) {
return $extraModuleVardefs;
}
foreach ($collection_list as $item) {
$itemLegacyModuleName = $item['module'] ?? '';
if (empty($itemLegacyModuleName)) {
continue;
}
$itemModule = $this->moduleNameMapper->toFrontEnd($itemLegacyModuleName);
if (empty($itemModule)) {
continue;
}
$itemVardefs = $this->getSubpanelModuleVardefs($itemModule);
if (empty($itemVardefs)) {
continue;
}
$extraModuleVardefs[$itemModule] = $itemVardefs;
}
return $extraModuleVardefs;
}
/**
* @param array $extraModuleVardefs
* @param int|string $key
* @param array $definition
* @return array
*/
protected function addMultiModuleVardefs(array $extraModuleVardefs, $key, array $definition): array
{
$multiModuleFieldVardefs = [];
foreach ($extraModuleVardefs as $module => $extraModuleVardef) {
$alias = $definition['alias'] ?? '';
if (empty($extraModuleVardef[$alias])) {
$alias = $key;
}
$fieldDefs = $this->getAliasDefinitions($this->fieldAliasMapper, $extraModuleVardef, $alias);
if (!empty($fieldDefs)) {
$fieldDefs['name'] = $definition['name'];
$fieldDefs['alias'] = $alias;
$multiModuleFieldVardefs[$module] = $fieldDefs;
}
}
$definition['multiModuleDefinitions'] = $multiModuleFieldVardefs;
return $definition;
}
}

View file

@ -1,8 +1,5 @@
{
"extends": "tslint:recommended",
"rulesDirectory": [
"codelyzer"
],
"rules": {
"align": {
"options": [

View file

@ -1,6 +1,6 @@
{
"name": "suitecrm",
"version": "8.6.0",
"version": "8.6.1",
"scripts": {
"ng": "ng",
"start": "npm run start:shell",
@ -89,7 +89,6 @@
"@typescript-eslint/eslint-plugin": "^2.34.0",
"@typescript-eslint/parser": "^2.34.0",
"barrelsby": "^2.2.0",
"codelyzer": "^6.0.0",
"eslint": "^6.8.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-import-resolver-typescript": "^2.3.0",

View file

@ -34,6 +34,8 @@ require __DIR__ . '/../vendor/autoload.php';
$kernel = new Kernel($_SERVER['APP_ENV'], (bool)$_SERVER['APP_DEBUG']);
$request = Request::createFromGlobals();
$kernel->init();
global $legacyRoute;
$legacyRoute = $kernel->getLegacyRoute($request);
@ -56,7 +58,7 @@ if (!empty($legacyRoute)) {
if (file_exists($legacyRoute['file'])) {
/* @noinspection PhpIncludeInspection */
require $legacyRoute['file'];
require './' . $legacyRoute['file'];
} else {
http_response_code(404);

View file

@ -0,0 +1,55 @@
<?php
/**
* SuiteCRM is a customer relationship management program developed by SalesAgility Ltd.
* Copyright (C) 2024 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
* Free Software Foundation with the addition of the following permission added
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
* IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses.
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Supercharged by SuiteCRM".
*/
trait HtmlFieldPurify
{
/**
* @param SugarBean $bean
* @param string $field
* @param mixed $value
* @return string
*/
protected function purify(SugarBean $bean, string $field, mixed $value): string
{
$fieldDef = $bean->field_defs[$field] ?? [];
$purifyHtml = $fieldDef['metadata']['purifyHtml'] ?? true;
if ($purifyHtml === false || !is_string($value)) {
return $value;
}
$extra = ['HTML.ForbiddenElements' => ['iframe' => true]];
$allowIframe = $fieldDef['metadata']['allowIframe'] ?? false;
if (isTrue($allowIframe)) {
$extra = [];
}
return purify_html(securexss($value), $extra);
}
}

View file

@ -27,9 +27,12 @@
require_once __DIR__ . '/../../../ApiBeanMapper/FieldMappers/FieldMapperInterface.php';
require_once __DIR__ . '/../../../ModuleNameMapper.php';
require_once __DIR__ . '/../../Helpers/HtmlFieldPurify.php';
class CaseUpdatesDescriptionMapper implements FieldMapperInterface
{
use HtmlFieldPurify;
public const FIELD_NAME = 'description';
/**
@ -51,7 +54,9 @@ class CaseUpdatesDescriptionMapper implements FieldMapperInterface
public function toApi(SugarBean $bean, array &$container, string $alternativeName = ''): void
{
$name = self::FIELD_NAME;
$container[$name] = html_entity_decode($bean->$name ?? '', ENT_QUOTES);
$value = html_entity_decode($bean->$name ?? '', ENT_QUOTES);
$container[$name] = html_entity_decode($this->purify($bean, $name, $value));
}
/**
@ -59,8 +64,10 @@ class CaseUpdatesDescriptionMapper implements FieldMapperInterface
*/
public function toBean(SugarBean $bean, array &$container, string $alternativeName = ''): void
{
$contents = $container[self::getField()] ?? [];
$container[self::getField()] = nl2br($contents);
$field = self::getField();
$value = nl2br($container[$field] ?? '');
$container[$field] = $this->purify($bean, $field,$value);
}
/**

View file

@ -26,9 +26,12 @@
*/
require_once __DIR__ . '/TypeMapperInterface.php';
require_once __DIR__ . '/../Helpers/HtmlFieldPurify.php';
class HtmlMapper implements TypeMapperInterface
{
use HtmlFieldPurify;
/**
* @inheritDoc
*/
@ -54,7 +57,9 @@ class HtmlMapper implements TypeMapperInterface
return;
}
$container[$newName] = $bean->$name;
$value = html_entity_decode($bean->$name);
$container[$newName] = $this->purify($bean, $name, $value);
}
/**
@ -68,15 +73,12 @@ class HtmlMapper implements TypeMapperInterface
$newName = $alternativeName;
}
$fieldDef = $bean->field_defs[$newName] ?? [];
$purifyHtml = $fieldDef['metadata']['purifyHtml'] ?? true;
$value = $container[$newName] ?? '';
if ($purifyHtml === false || empty($value) || !is_string($value)) {
if (empty($value)) {
return;
}
$container[$newName] = purify_html(securexss($value));
$container[$newName] = $this->purify($bean, $name, $value);
}
}

View file

@ -26,9 +26,12 @@
*/
require_once __DIR__ . '/TypeMapperInterface.php';
require_once __DIR__ . '/../Helpers/HtmlFieldPurify.php';
class TextMapper implements TypeMapperInterface
{
use HtmlFieldPurify;
/**
* @inheritDoc
*/
@ -54,7 +57,12 @@ class TextMapper implements TypeMapperInterface
return;
}
$container[$newName] = $bean->$name;
$value = $bean->$name;
if (is_string($value) ) {
$value = html_entity_decode($value);
}
$container[$newName] = $this->purify($bean, $name, $value);
}
/**
@ -68,15 +76,15 @@ class TextMapper implements TypeMapperInterface
$newName = $alternativeName;
}
$value = $container[$newName] ?? '';
$fieldDef = $bean->field_defs[$newName] ?? [];
$editor = $fieldDef['editor'] ?? '';
$purifyHtml = $fieldDef['metadata']['purifyHtml'] ?? true;
if (empty($editor) || $editor !== 'html' || $purifyHtml === false || !is_string($container[$newName] ?? '')) {
if (empty($editor) || $editor !== 'html' || !is_string($value)) {
return;
}
$container[$newName] = purify_html(securexss($container[$newName] ?? ''));
$container[$newName] = $this->purify($bean, $name, $value);
}
}

View file

@ -7,5 +7,5 @@ function survey_url_display(Surveys $survey)
global $sugar_config;
$url = $sugar_config['site_url'] . "/index.php?entryPoint=survey&id=" . $survey->id;
return "<a href='$url'>$url</a>";
return "<a href='$url' target='_blank'>$url</a>";
}

View file

@ -891,9 +891,6 @@
"tinymce/tinymce": {
"version": "4.9.11"
},
"tuupola/slim-jwt-auth": {
"version": "2.4.0"
},
"twig/twig": {
"version": "v2.12.3"
},

2799
yarn.lock

File diff suppressed because it is too large Load diff