Moderate severityNVD Advisory· Published Sep 20, 2022· Updated May 27, 2025
Cross-site Scripting (XSS) - Stored in yetiforcecompany/yetiforcecrm
CVE-2022-3005
Description
Cross-site Scripting (XSS) - Stored in GitHub repository yetiforcecompany/yetiforcecrm prior to 6.4.0.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
yetiforce/yetiforce-crmPackagist | <= 6.4.0 | — |
Affected products
1- Range: unspecified
Patches
1e55886781509Improved SLA Policy elements
10 files changed · +251 −235
config/version.php+1 −1 modified@@ -1,7 +1,7 @@ <?php return [ - 'appVersion' => '6.4.15', + 'appVersion' => '6.4.16', 'patchVersion' => '2022.08.26', 'lib_roundcube' => '0.3.1', ];
languages/en-US/ServiceContracts.json+0 −8 modified@@ -48,13 +48,5 @@ "LBL_STATUS": "Status", "LBL_CONDITIONS": "Conditions", "LBL_TIMES": "Times" - }, - "js": { - "JS_POLICY_NAME": "Policy name", - "JS_OPERATIONAL_HOURS": "Operational hours", - "JS_REACTION_TIME": "Reaction time", - "JS_IDLE_TIME": "Idle time", - "JS_RESOLVE_TIME": "Resolve time", - "JS_BUSINESS_HOURS": "Business hours" } }
layouts/basic/modules/ServiceContracts/CustomConditions.tpl+44 −51 modified@@ -1,67 +1,60 @@ {*<!-- {[The file is published on the basis of YetiForce Public License 5.0 that can be found in the following directory: licenses/LicenseEN.txt or yetiforce.com]} -->*} {strip} - <!-- tpl-ServiceContracts-CustomConditions --> - <input type="hidden" class="js-all-business-hours" value="{\App\Purifier::encodeHtml(\App\Json::encode($ALL_BUSINESS_HOURS))}"> - <div class="d-none js-conditions-template" data-js="container"> - {include file=\App\Layout::getTemplatePath('ConditionBuilder.tpl', $MODULE_NAME) ADVANCE_CRITERIA=[]} - </div> - <div class="js-custom-conditions" data-js="container"> - {foreach item=ROW from=$SLA_POLICY_ROWS key=$ROW_INDEX} - {if $ROW['policy_type']===2} - <div class="card js-custom-row shadow-sm mb-2" data-id="{$ROW['id']}" data-record-id="{$RECORD->getId()}" data-js="container"> - <div class="card-body"> - <div class="d-flex"> - <div class="d-block" style="flex-grow:1"> - <div class="row no-gutters"> - <div class="col-5 pr-2"> - {assign var=ROW_HOURS value=explode(',', $ROW['business_hours'])} - <label>{\App\Language::translate('LBL_BUSINESS_HOURS', 'ServiceContracts')}</label> - <div> - <select class="select2 js-business-hours" name="business_hours[{$ROW_INDEX}][]" multiple data-validation-engine="validate[required,funcCall[Vtiger_Base_Validator_Js.invokeValidation]]"> - {foreach item=BUSINESS_HOURS from=$ALL_BUSINESS_HOURS} - <option value="{$BUSINESS_HOURS['id']}" {if in_array($BUSINESS_HOURS['id'], $ROW_HOURS)}selected="selected" {/if}>{$BUSINESS_HOURS['name']}</option> - {/foreach} - </select> - </div> + {foreach item=ROW from=$SLA_POLICY_ROWS key=$ROW_INDEX} + {if $ROW['policy_type']===2} + <div class="card js-custom-row shadow-sm mb-2" data-id="{$ROW['id']}" data-record-id="{$RECORD->getId()}" data-js="container"> + <div class="card-body"> + <div class="d-flex"> + <div class="d-block" style="flex-grow:1"> + <div class="row no-gutters"> + <div class="col-5 pr-2"> + {assign var=ROW_HOURS value=explode(',', $ROW['business_hours'])} + <label>{\App\Language::translate('LBL_BUSINESS_HOURS', 'ServiceContracts')}</label> + <div> + <select class="select2 js-business-hours" name="business_hours[{$ROW_INDEX}][]" multiple data-validation-engine="validate[required,funcCall[Vtiger_Base_Validator_Js.invokeValidation]]"> + {foreach item=BUSINESS_HOURS from=$ALL_BUSINESS_HOURS} + <option value="{$BUSINESS_HOURS['id']}" {if in_array($BUSINESS_HOURS['id'], $ROW_HOURS)}selected="selected" {/if}>{$BUSINESS_HOURS['name']}</option> + {/foreach} + </select> </div> - <div class="col-2 pr-2"> - <label>{\App\Language::translate('LBL_REACTION_TIME','ServiceContracts')}</label> - <div class="input-group time"> - <input type="hidden" name="reaction_time[{$ROW_INDEX}]" class="c-time-period" value="{$ROW['reaction_time']}"> - </div> - </div> - <div class="col-2 pr-2"> - <label>{\App\Language::translate('LBL_IDLE_TIME','ServiceContracts')}</label> - <div class="input-group time"> - <input type="hidden" name="idle_time[{$ROW_INDEX}]" class="c-time-period" value="{$ROW['idle_time']}"> - </div> + </div> + <div class="col-2 pr-2"> + <label>{\App\Language::translate('LBL_REACTION_TIME','ServiceContracts')}</label> + <div class="input-group time"> + <input type="hidden" name="reaction_time[{$ROW_INDEX}]" class="c-time-period" value="{$ROW['reaction_time']|escape}"> </div> - <div class="col-2 pr-2"> - <label>{\App\Language::translate('LBL_RESOLVE_TIME','ServiceContracts')}</label> - <div class="input-group time"> - <input type="hidden" name="resolve_time[{$ROW_INDEX}]" class="c-time-period" value="{$ROW['resolve_time']}"> - </div> + </div> + <div class="col-2 pr-2"> + <label>{\App\Language::translate('LBL_IDLE_TIME','ServiceContracts')}</label> + <div class="input-group time"> + <input type="hidden" name="idle_time[{$ROW_INDEX}]" class="c-time-period" value="{$ROW['idle_time']|escape}"> </div> </div> - <div class="row mt-2"> - <div class="js-conditions-col col"> - <label>{\App\Language::translate('LBL_CONDITIONS', $MODULE_NAME)}</label> - <input type="hidden" name="rowid[{$ROW_INDEX}]" value="{$ROW['id']}" class="js-custom-row-id" /> - <input type="hidden" name="conditions[{$ROW_INDEX}]" class="js-conditions-value" value="{\App\Purifier::encodeHtml($ROW['conditions'])}" data-js="container"> - {include file=\App\Layout::getTemplatePath('ConditionBuilder.tpl', $MODULE_NAME) ADVANCE_CRITERIA=\App\Json::decode($ROW['conditions'])} + <div class="col-2 pr-2"> + <label>{\App\Language::translate('LBL_RESOLVE_TIME','ServiceContracts')}</label> + <div class="input-group time"> + <input type="hidden" name="resolve_time[{$ROW_INDEX}]" class="c-time-period" value="{$ROW['resolve_time']|escape}"> </div> </div> </div> - <div class="d-inline-flex text-right border-left" style="flex-grow:0"> - <div class="d-inline-block align-center" style="margin:auto 0;"> - <a href class="btn btn-danger ml-4 js-delete-row-action"><span class="fas fa-trash-alt"></span></a> + <div class="row mt-2"> + <div class="js-conditions-col col"> + <label>{\App\Language::translate('LBL_CONDITIONS', $MODULE_NAME)}</label> + <input type="hidden" name="rowid[{$ROW_INDEX}]" value="{$ROW['id']}" class="js-custom-row-id" /> + <input type="hidden" name="conditions[{$ROW_INDEX}]" class="js-conditions-value" value="{\App\Purifier::encodeHtml($ROW['conditions'])}" data-js="container"> + {include file=\App\Layout::getTemplatePath('ConditionBuilder.tpl', $MODULE_NAME) ADVANCE_CRITERIA=\App\Json::decode($ROW['conditions'])} </div> </div> </div> + <div class="d-inline-flex text-right border-left" style="flex-grow:0"> + <div class="d-inline-block align-center" style="margin:auto 0;"> + <a href class="btn btn-danger ml-4 js-delete-row-action"><span class="fas fa-trash-alt"></span></a> + </div> + </div> </div> </div> - {/if} - {/foreach} - </div> + </div> + {/if} + {/foreach} <!-- /tpl-ServiceContracts-CustomConditions --> {/strip}
layouts/basic/modules/ServiceContracts/SlaPolicyCustom.tpl+41 −0 added@@ -0,0 +1,41 @@ +{*<!-- {[The file is published on the basis of YetiForce Public License 5.0 that can be found in the following directory: licenses/LicenseEN.txt or yetiforce.com]} -->*} +{strip} + <!-- tpl-ServiceContracts-SlaPolicyCustom --> + <div class="js-sla-policy relatedContainer" data-js="container"> + <input type="hidden" name="target" value="{$TARGET_MODULE}"> + <div class="form-group row text-center"> + <div class="col-12 flex"> + <label class="d-inline-block mr-2"> + {\App\Language::translate('LBL_POLICY_TYPE', $MODULE_NAME)}: + </label> + <label class="d-inline-block mr-2"> + <input type="radio" name="policy_type" class="form-control d-inline-block mr-1 js-sla-policy-type-radio" value="0" {if $POLICY_TYPE===0} checked="checked" {/if} />{\App\Language::translate('LBL_POLICY_TYPE_GLOBAL', $MODULE_NAME)} + </label> + <label class="d-inline-block mr-2"> + <input type="radio" name="policy_type" class="form-control d-inline-block mr-1 js-sla-policy-type-radio" value="1" {if $POLICY_TYPE===1} checked="checked" {/if} />{\App\Language::translate('LBL_POLICY_TYPE_TEMPLATE', $MODULE_NAME)} + </label> + <label class="d-inline-block mr-2"> + <input type="radio" name="policy_type" class="form-control d-inline-block mr-1 js-sla-policy-type-radio" value="2" {if $POLICY_TYPE===2} checked="checked" {/if} /> {\App\Language::translate('LBL_POLICY_TYPE_CUSTOM', $MODULE_NAME)} + </label> + <button class="js-sla-policy-custom js-sla-policy-add-record-btn btn btn-success float-right d-none" data-record-id="{$RECORD->getId()}"> + <span class="fas fa-plus"></span> {\App\Language::translate('LBL_ADD_ENTRY', $MODULE_NAME)} + </button> + </div> + </div> + <div class="js-sla-policy-template js-sla-policy-template--container form-group row d-none" data-js="container"></div> + <div class="js-sla-policy-custom form-group row d-none" data-js="container"> + <div class="col-12"> + {include file=\App\Layout::getTemplatePath('CustomConditions.tpl', $MODULE_NAME)} + </div> + </div> + <div class="row"> + <div class="col text-center"> + <button class="btn btn-success js-sla-policy-save-btn"> + <span class="fas fa-check mr-2"></span> + {\App\Language::translate('LBL_SAVE')} + </button> + </div> + </div> + </div> + <!-- /tpl-ServiceContracts-SlaPolicyCustom --> +{/strip}
layouts/basic/modules/ServiceContracts/SlaPolicyTemplate.tpl+31 −0 added@@ -0,0 +1,31 @@ +{*<!-- {[The file is published on the basis of YetiForce Public License 5.0 that can be found in the following directory: licenses/LicenseEN.txt or yetiforce.com]} -->*} +{strip} + <!-- tpl-ServiceContracts-SlaPolicyTemplate --> + <div class="col-12"> + <table class="table js-sla-policy-template-table"> + <thead> + <tr> + <th></th> + <th>{\App\Language::translate('LBL_POLICY_NAME', $MODULE_NAME)}</th> + <th>{\App\Language::translate('LBL_OPERATIONAL_HOURS', $MODULE_NAME)}</th> + <th>{\App\Language::translate('LBL_REACTION_TIME', $MODULE_NAME)}</th> + <th>{\App\Language::translate('LBL_IDLE_TIME', $MODULE_NAME)}</th> + <th>{\App\Language::translate('LBL_RESOLVE_TIME', $MODULE_NAME)}</th> + </tr> + </thead> + <tbody> + {foreach from=\App\Utils\ServiceContracts::getSlaPolicyByModule($TARGET_MODULE_ID) item=ROW key=key name=slaTemplates} + <tr> + <td><input type="radio" name="policy_id" value="{$ROW['id']}" {if $SELECTED_TEMPLATE === $ROW['id'] || (!$SELECTED_TEMPLATE && $smarty.foreach.slaTemplates.first)} checked="checked" {/if}></td> + <td>{\App\Purifier::encodeHtml($ROW.name)}</td> + <td>{\App\Purifier::encodeHtml($ROW.operational_hours)}</td> + <td>{\App\Purifier::encodeHtml($ROW.reaction_time)}</td> + <td>{\App\Purifier::encodeHtml($ROW.idle_time)}</td> + <td>{\App\Purifier::encodeHtml($ROW.resolve_time)}</td> + </tr> + {/foreach} + </tbody> + </table> + </div> + <!-- /tpl-ServiceContracts-SlaPolicyTemplate --> +{/strip}
layouts/basic/modules/ServiceContracts/SlaPolicy.tpl+3 −1 modified@@ -25,7 +25,9 @@ <div class="js-sla-policy-template js-sla-policy-template--container form-group row d-none" data-js="container"></div> <div class="js-sla-policy-custom form-group row d-none" data-js="container"> <div class="col-12"> - {include file=\App\Layout::getTemplatePath('CustomConditions.tpl', $MODULE_NAME)} + <div class="js-custom-conditions" data-js="container"> + {include file=\App\Layout::getTemplatePath('CustomConditions.tpl', $MODULE_NAME)} + </div> </div> </div> <div class="row">
layouts/basic/modules/Settings/SlaPolicy/EditViewBlocks.tpl+6 −6 modified@@ -21,7 +21,7 @@ <div class="card-header"> {if !empty($RECORD->getId())} <span class="yfi yfi-full-editing-view mr-2"></span> - {\App\Language::translate('LBL_EDIT',$QUALIFIED_MODULE)} - {$RECORD->getName()} + {\App\Language::translate('LBL_EDIT',$QUALIFIED_MODULE)} - {\App\Purifier::encodeHtml($RECORD->getName())} {else} <span class="fas fa-plus mr-2"></span> {\App\Language::translate('LBL_CREATE',$QUALIFIED_MODULE)} @@ -31,13 +31,13 @@ <div class="form-group row"> <div class="col-12 col-md-3"> <label>{\App\Language::translate('LBL_NAME',$QUALIFIED_MODULE)}</label> - <input type="text" name="name" class="form-control" value="{$RECORD->getName()}" data-validation-engine="validate[required,maxSize[255]]"> + <input type="text" name="name" class="form-control" value="{\App\Purifier::encodeHtml($RECORD->getName())}" data-validation-engine="validate[required,maxSize[255]]"> </div> <div class="col-12 col-md-3"> <label>{\App\Language::translate('LBL_SOURCE_MODULE',$QUALIFIED_MODULE)}</label> <select name="source_module" class="select2" data-validation-engine="validate[required]"> {foreach item=MODULE_NAME from=$MODULES} - <option value="{$MODULE_NAME}" {if \App\Module::getModuleName($RECORD->get('tabid')) === $MODULE_NAME}selected="selected" {/if}>{\App\Language::translate($MODULE_NAME, $MODULE_NAME)}</option> + <option value="{$MODULE_NAME|escape}" {if \App\Module::getModuleName($RECORD->get('tabid')) === $MODULE_NAME}selected="selected" {/if}>{\App\Language::translate($MODULE_NAME, $MODULE_NAME)}</option> {/foreach} </select> </div> @@ -66,19 +66,19 @@ <div class="col-12 col-md-4"> <label>{\App\Language::translate('LBL_REACTION_TIME','ServiceContracts')}</label> <div class="input-group time"> - <input type="hidden" name="reaction_time" class="c-time-period" value="{$RECORD->get('reaction_time')}"> + <input type="hidden" name="reaction_time" class="c-time-period" value="{$RECORD->get('reaction_time')|escape}"> </div> </div> <div class="col-12 col-md-4"> <label>{\App\Language::translate('LBL_IDLE_TIME','ServiceContracts')}</label> <div class="input-group time"> - <input type="hidden" name="idle_time" class="c-time-period" value="{$RECORD->get('idle_time')}"> + <input type="hidden" name="idle_time" class="c-time-period" value="{$RECORD->get('idle_time')|escape}"> </div> </div> <div class="col-12 col-md-4"> <label>{\App\Language::translate('LBL_RESOLVE_TIME','ServiceContracts')}</label> <div class="input-group time"> - <input type="hidden" name="resolve_time" class="c-time-period" value="{$RECORD->get('resolve_time')}"> + <input type="hidden" name="resolve_time" class="c-time-period" value="{$RECORD->get('resolve_time')|escape}"> </div> </div> </div>
modules/ServiceContracts/actions/PolicyTemplatesAjax.php+0 −48 removed@@ -1,48 +0,0 @@ -<?php -/** - * ServiceContracts PolicyTemplatesAjax Action class. - * - * @package Action - * - * @copyright YetiForce S.A. - * @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com) - * @author Rafal Pospiech <r.pospiech@yetiforce.com> - * @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com> - */ -class ServiceContracts_PolicyTemplatesAjax_Action extends \App\Controller\Action -{ - /** {@inheritdoc} */ - public function checkPermission(App\Request $request) - { - $record = Vtiger_DetailView_Model::getInstance($request->getModule(), $request->getInteger('record')); - if (!$record->getRecord()->isViewable()) { - throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406); - } - } - - /** {@inheritdoc} */ - public function process(App\Request $request) - { - $sla = \App\Utils\ServiceContracts::getSlaPolicyForServiceContracts($request->getInteger('record')); - $slaId = $sla ? $sla[0]['sla_policy_id'] : false; - $rows = []; - foreach (\App\Utils\ServiceContracts::getSlaPolicyByModule(\App\Module::getModuleId($request->getByType('targetModule', 'Alnum'))) as $row) { - $moduleName = \App\Module::getModuleName($row['tabid']); - $row['tabid'] = \App\Language::translate($moduleName, $moduleName); - $row['operational_hours'] = $row['operational_hours'] ? \App\Language::translate('LBL_CALENDAR_HOURS', 'ServiceContracts') : \App\Language::translate('LBL_BUSINESS_HOURS', 'ServiceContracts'); - $row['business_hours'] = implode(', ', array_column(\App\Utils\ServiceContracts::getBusinessHoursByIds(explode(',', $row['business_hours'])), 'name')); - $row['reaction_time'] = \App\Fields\TimePeriod::getLabel($row['reaction_time']); - $row['idle_time'] = \App\Fields\TimePeriod::getLabel($row['idle_time']); - $row['resolve_time'] = \App\Fields\TimePeriod::getLabel($row['resolve_time']); - if ($row['id'] === $slaId) { - $row['checked'] = true; - } else { - $row['checked'] = false; - } - $rows[] = $row; - } - $response = new Vtiger_Response(); - $response->setResult($rows); - $response->emit(); - } -}
modules/ServiceContracts/views/PolicyTemplatesAjax.php+73 −0 added@@ -0,0 +1,73 @@ +<?php +/** + * ServiceContracts PolicyTemplatesAjax View class. + * + * @package View + * + * @copyright YetiForce S.A. + * @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com) + * @author Radosław Skrzypczak <r.skrzypczak@yetiforce.com> + */ +class ServiceContracts_PolicyTemplatesAjax_View extends Vtiger_Index_View +{ + use \App\Controller\ExposeMethod; + + /** @var Vtiger_Record_Model Record model instance. */ + public $record; + + /** + * Construct. + */ + public function __construct() + { + parent::__construct(); + $this->exposeMethod('slaPolicyTemplate'); + $this->exposeMethod('slaPolicyCustom'); + } + + /** {@inheritdoc} */ + public function checkPermission(App\Request $request) + { + $this->record = Vtiger_Record_Model::getInstanceById($request->getInteger('record'), $request->getModule()); + if (!$this->record->isViewable() || !$this->record->isPermitted('ServiceContractsSla') || !App\Privilege::isPermitted($request->getByType('targetModule', \App\Purifier::ALNUM))) { + throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406); + } + } + + /** {@inheritdoc} */ + public function slaPolicyTemplate(App\Request $request) + { + $moduleName = $request->getModule(); + $sla = \App\Utils\ServiceContracts::getSlaPolicyForServiceContracts($request->getInteger('record')); + $slaId = $sla[0]['sla_policy_id'] ?? 0; + + $viewer = $this->getViewer($request); + $viewer->assign('TARGET_MODULE_ID', \App\Module::getModuleId($request->getByType('targetModule', \App\Purifier::ALNUM))); + $viewer->assign('SELECTED_TEMPLATE', $slaId); + + return $viewer->view('SlaPolicyTemplate.tpl', $moduleName); + } + + /** {@inheritdoc} */ + public function slaPolicyCustom(App\Request $request) + { + $moduleName = $request->getModule(); + $index = $request->getInteger('index', time()); + $defaultEmptyData = [ + 'id' => 0, + 'policy_type' => 2, + 'conditions' => '[]', + 'reaction_time' => '1:d', + 'idle_time' => '1:d', + 'resolve_time' => '1:d', + 'business_hours' => '', + ]; + + $viewer = $this->getViewer($request); + $viewer->assign('RECORD', $this->record); + $viewer->assign('ALL_BUSINESS_HOURS', \App\Utils\ServiceContracts::getAllBusinessHours()); + $viewer->assign('SLA_POLICY_ROWS', [$index => $defaultEmptyData]); + + return $viewer->view('CustomConditions.tpl', $moduleName); + } +}
public_html/layouts/basic/modules/ServiceContracts/resources/Detail.js+52 −120 modified@@ -4,6 +4,7 @@ * @description InRelation scripts for SlaPolicy module * @license YetiForce Public License 5.0 * @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com> + * @author Radosław Skrzypczak <r.skrzypczak@yetiforce.com> */ 'use strict'; @@ -40,73 +41,45 @@ Vtiger_Detail_Js( this.container.find('.js-sla-policy-custom').removeClass('d-none'); return this; }, - /** - * Get template table - * @param {Array} rows - * - * @returns {String} HTML + * Get default params + * @returns {Object} */ - getTemplateTableHtml(rows) { - let somethingChecked = false; - rows.forEach((row) => { - if (row.checked) { - somethingChecked = true; - return false; - } - }); - if (!somethingChecked && typeof rows[0] !== 'undefined') { - rows[0].checked = true; - } - return `<div class="col-12"><table class="table js-sla-policy-template-table"> - <thead> - <tr> - <th></th> - <th>${app.vtranslate('JS_POLICY_NAME')}</th> - <th>${app.vtranslate('JS_OPERATIONAL_HOURS')}</th> - <th>${app.vtranslate('JS_REACTION_TIME')}</th> - <th>${app.vtranslate('JS_IDLE_TIME')}</th> - <th>${app.vtranslate('JS_RESOLVE_TIME')}</th> - </tr> - </thead> - <tbody> - ${rows - .map((row) => { - return `<tr> - <td><input type="radio" name="policy_id" value="${row.id}"${row.checked ? 'checked="checked"' : ''}></td> - <td>${row.name}</td> - <td>${row.operational_hours}</td> - <td>${row.reaction_time}</td> - <td>${row.idle_time}</td> - <td>${row.resolve_time}</td> - </tr>`; - }) - .join('')} - </tbody> - </table> - </div>`; + getDefaultParam() { + return { + module: 'ServiceContracts', + view: 'PolicyTemplatesAjax', + targetModule: this.targetModule, + record: Number($('#recordId').val()) + }; }, /** * Load predefined sla policy templates + * @param {Object} param + * @returns */ - loadTemplates() { + loadTemplates(param) { const progress = jQuery.progressIndicator({ position: 'html', blockInfo: { enabled: true } }); - AppConnector.request({ - module: 'ServiceContracts', - action: 'PolicyTemplatesAjax', - targetModule: this.targetModule, - record: Number($('#recordId').val()) - }).done((data) => { - progress.progressIndicator({ mode: 'hide' }); - if (data.success) { - this.container.find('.js-sla-policy-template--container').html(this.getTemplateTableHtml(data.result)); - } + return new Promise((resolve, _reject) => { + AppConnector.request(param) + .done((data) => { + progress.progressIndicator({ mode: 'hide' }); + resolve(data); + }) + .fail((e, t) => { + progress.progressIndicator({ mode: 'hide' }); + app.errorLog(e, t); + app.showNotify({ + text: app.vtranslate('JS_ERROR'), + type: 'error' + }); + }); }); }, @@ -116,7 +89,12 @@ Vtiger_Detail_Js( onPolicyTypeChange() { this.policyType = Number(this.container.find('[name="policy_type"]:checked').val()); if (this.policyType === 1) { - this.hideAll().showTemplateSettings().loadTemplates(); + this.hideAll() + .showTemplateSettings() + .loadTemplates({ mode: 'slaPolicyTemplate', ...this.getDefaultParam() }) + .then((data) => { + this.container.find('.js-sla-policy-template--container').html(data); + }); } else if (this.policyType === 2) { this.hideAll().showCustomSettings(); } else { @@ -176,7 +154,7 @@ Vtiger_Detail_Js( rowElem.find('.js-custom-row-id').val(row.id); }); } else { - $.each(this.container.find('.js-custom-row'), (index, rowElem) => { + $.each(this.container.find('.js-custom-row'), (_index, rowElem) => { rowElem = $(rowElem); rowElem.data('id', 0); rowElem.find('.js-custom-row-id').val(0); @@ -198,66 +176,21 @@ Vtiger_Detail_Js( addPolicyBtn.on('click', (e) => { e.preventDefault(); e.stopPropagation(); - const index = this.container.find('.js-custom-row').length; - const row = $(`<div class="card js-custom-row shadow-sm mb-2" data-id="0" data-record-id="` + addPolicyBtn.data('record-id') + `" data-js="container"> - <div class="card-body"> - <div class="d-flex"> - <div class="d-block" style="flex-grow:1"> - <div class="row no-gutters"> - <div class="col-5 pr-2"> - <label>${app.vtranslate('JS_BUSINESS_HOURS')}</label> - <select class="select2" name="business_hours[${index}][]" multiple data-validation-engine="validate[required,funcCall[Vtiger_Base_Validator_Js.invokeValidation]]"> - ${this.businessHours - .map((businessHours) => { - return `<option value="${businessHours.id}">${businessHours.name}</option>`; - }) - .join('')} - </select> - </div> - <div class="col-2 pr-2"> - <label>${app.vtranslate('JS_REACTION_TIME')}</label> - <div class="input-group time"> - <input type="hidden" name="reaction_time[${index}]" class="c-time-period" value="1:d"> - </div> - </div> - <div class="col-2 pr-2"> - <label>${app.vtranslate('JS_IDLE_TIME')}</label> - <div class="input-group time"> - <input type="hidden" name="idle_time[${index}]" class="c-time-period" value="1:d"> - </div> - </div> - <div class="col-2 pr-2"> - <label>${app.vtranslate('JS_RESOLVE_TIME')}</label> - <div class="input-group time"> - <input type="hidden" name="resolve_time[${index}]" class="c-time-period" value="1:d"> - </div> - </div> - </div> - <div class="row mt-2"> - <div class="js-conditions-col col"> - <input type="hidden" name="rowid[${index}]" value="0" class="js-custom-row-id" /> - <input type="hidden" name="conditions[${index}]" class="js-conditions-value" value="{}" data-js="container"> - ${this.container.find('.js-conditions-template').html()} - </div> - </div> - </div> - <div class="d-inline-flex text-right border-left" style="flex-grow:0"> - <div class="d-inline-block align-center" style="margin:auto 0;"> - <a href class="btn btn-danger ml-4 js-delete-row-action"><span class="fas fa-trash-alt"></span></a> - </div> - </div> - </div> - </div> - </div>` - ); - App.Fields.TimePeriod.register(row); - this.registerDelBtnClick(row); - App.Fields.Picklist.showSelect2ElementView(row.find('.select2')); - this.registerConditionBuilder( - row.find('.js-condition-builder').eq(0), - this.container.find('.js-conditions-col').length - ); - this.container.find('.js-custom-conditions').append(row); + this.loadTemplates({ + mode: 'slaPolicyCustom', + index: this.container.find('.js-custom-row').length, + ...this.getDefaultParam() + }).then((data) => { + let html = $(data); + App.Fields.TimePeriod.register(html); + this.registerDelBtnClick(html); + App.Fields.Picklist.showSelect2ElementView(html.find('.select2')); + this.registerConditionBuilder( + html.find('.js-condition-builder').eq(0), + this.container.find('.js-conditions-col').length + ); + this.container.find('.js-custom-conditions').append(html); + }); }); }, @@ -288,7 +221,7 @@ Vtiger_Detail_Js( targetModule: this.targetModule, record: row.data('record-id'), rowId: rowId - }).done((data) => { + }).done(() => { progress.progressIndicator({ mode: 'hide' }); $(e.target).closest('.card').remove(); app.showNotify({ @@ -336,11 +269,10 @@ Vtiger_Detail_Js( this.container = this.getForm(); this.policyType = Number(this.container.find('[name="policy_type"]:checked').val()); this.targetModule = this.container.find('[name="target"]').val(); - this.businessHours = JSON.parse(this.container.find('.js-all-business-hours').val()); this.conditionBuilders = []; this.conditionsBuildersContainers = []; this.container.off('submit').on('submit', this.onSubmit.bind(this)); - this.container.find('.js-sla-policy-type-radio').on('click', (e) => this.onPolicyTypeChange()); + this.container.find('.js-sla-policy-type-radio').on('click', () => this.onPolicyTypeChange()); this.onPolicyTypeChange(); App.Fields.TimePeriod.register(this.container); this.registerAddRecordBtnClick(); @@ -356,7 +288,7 @@ Vtiger_Detail_Js( if (detailViewForm.find('.js-sla-policy').length) { this.initSlaPolicy(); } - app.event.on('DetailView.Tab.AfterLoad', (event, data, instance) => { + app.event.on('DetailView.Tab.AfterLoad', (_event, _data, instance) => { if (instance.getForm().find('.js-sla-policy').length) { instance.initSlaPolicy(); }
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-vx3x-hwph-grvwghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-3005ghsaADVISORY
- github.com/yetiforcecompany/yetiforcecrm/commit/e55886781509fe39951fc7528347696474a17884ghsax_refsource_MISCWEB
- huntr.dev/bounties/4b144433-a979-4c4e-a627-659838acc217ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.