Cross-site Scripting (XSS) in livehelperchat/livehelperchat
Description
Cross-site Scripting (XSS) in GitHub repository livehelperchat/livehelperchat prior to 3.99v. The attacker can execute malicious JavaScript on the application.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Stored XSS vulnerability in Live Helper Chat prior to 3.99v allows an attacker to inject malicious JavaScript through chat trigger action commands.
Vulnerability
A cross-site scripting (XSS) vulnerability exists in the Live Helper Chat application prior to version 3.99v. The bug is located in the NodeTriggerActionCommand component, where user-controlled input for chat variable values and group method fields is not properly sanitized before being rendered in the browser. Specifically, the payload and payload_cond_field inputs are stored and later displayed without output encoding, allowing the injection of arbitrary JavaScript. The vulnerability is reachable when an operator with the ability to configure trigger actions saves a malicious payload in the chat trigger settings [1][2][3][4].
Exploitation
An attacker needs to have access to the Live Helper Chat administration interface with privileges to create or edit trigger actions. The attacker crafts a malicious payload (e.g., ``) in the chat variable value input field or the group method field of a trigger action. When an operator views or interacts with the affected trigger configuration in the management panel, the stored payload executes in their browser session. No additional user interaction beyond viewing the configuration page is required [2][3][4].
Impact
Successful exploitation enables the attacker to execute arbitrary JavaScript in the context of the victim operator's browser. This can lead to session hijacking, data exfiltration (e.g., chat logs, customer data), or further administrative actions performed on behalf of the victim. The compromise is confined to the browser session of operators who access the maliciously modified trigger configuration [3][4].
Mitigation
The vulnerability is fixed in version 3.99v, released on April 29, 2022. The commit edef7a8 applies proper sanitization to the affected input fields. Users should upgrade to version 3.99v or later. There are no known workarounds for unpatched versions. The CVE is not listed in CISA's Known Exploited Vulnerabilities catalog [2][3][4].
- GitHub - LiveHelperChat/livehelperchat: Live Helper Chat - live support for your website. Featuring web and mobile apps, Voice & Video & ScreenShare. Supports Telegram, Twilio (whatsapp), Facebook messenger including building a bot.
- 3.99v · LiveHelperChat/livehelperchat@edef7a8
- NVD - CVE-2022-1530
- The world’s first bug bounty platform for AI/ML
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
remdex/livehelperchatPackagist | < 3.99 | 3.99 |
Affected products
3- osv-coords2 versions
< 3.99.0+ 1 more
- (no CPE)range: < 3.99.0
- (no CPE)range: < 3.99
- livehelperchat/livehelperchat/livehelperchatv5Range: unspecified
Patches
1edef7a8387be3.99v
40 files changed · +411 −343
lhc_web/cli/lib/install.php+1 −1 modified@@ -1947,7 +1947,7 @@ function step3() { $db->query("CREATE TABLE `lh_webhook` ( `id` int(11) NOT NULL AUTO_INCREMENT, `event` varchar(50) NOT NULL, `bot_id_alt` int(11) NOT NULL DEFAULT '0', `trigger_id_alt` int(11) NOT NULL DEFAULT '0',`bot_id` int(11) NOT NULL, `trigger_id` int(11) NOT NULL, `disabled` tinyint(1) NOT NULL, `configuration` longtext NOT NULL, `type` tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), KEY `event_disabled` (`event`,`disabled`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); $db->query("CREATE TABLE `lh_incoming_webhook` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL,`identifier` varchar(50) NOT NULL, `scope` varchar(50) NOT NULL, `dep_id` int(11) NOT NULL, `disabled` tinyint(1) NOT NULL, `configuration` longtext NOT NULL, PRIMARY KEY (`id`), KEY `identifier` (`identifier`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); $db->query("CREATE TABLE `lh_chat_incoming` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `chat_id` bigint(20) NOT NULL, `utime` bigint(20) NOT NULL, `incoming_id` int(11) NOT NULL, `payload` longtext NOT NULL, `chat_external_id` varchar(50) NOT NULL, PRIMARY KEY (`id`), KEY `chat_id` (`chat_id`), KEY `incoming_ext_id` (`incoming_id`,`chat_external_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); - $db->query("CREATE TABLE `lh_abstract_chat_column` (`id` int(11) NOT NULL AUTO_INCREMENT,`column_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,`variable` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `position` int(11) NOT NULL, `enabled` tinyint(1) NOT NULL, `online_enabled` tinyint(1) NOT NULL, `chat_enabled` tinyint(1) NOT NULL, `conditions` text COLLATE utf8mb4_unicode_ci NOT NULL,`column_icon` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `column_identifier` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`id`), KEY `enabled` (`enabled`), KEY `online_enabled` (`online_enabled`), KEY `chat_enabled` (`chat_enabled`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); + $db->query("CREATE TABLE `lh_abstract_chat_column` (`id` int(11) NOT NULL AUTO_INCREMENT,`column_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `has_popup` tinyint(1) NOT NULL DEFAULT 0, `popup_content` longtext COLLATE utf8mb4_unicode_ci NOT NULL, `icon_mode` tinyint(1) NOT NULL DEFAULT 0, `variable` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `position` int(11) NOT NULL, `enabled` tinyint(1) NOT NULL, `online_enabled` tinyint(1) NOT NULL, `chat_enabled` tinyint(1) NOT NULL, `conditions` text COLLATE utf8mb4_unicode_ci NOT NULL,`column_icon` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `column_identifier` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`id`), KEY `enabled` (`enabled`), KEY `online_enabled` (`online_enabled`), KEY `chat_enabled` (`chat_enabled`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); $db->query("CREATE TABLE `lh_abstract_chat_priority` (`id` int(11) NOT NULL AUTO_INCREMENT,`value` text COLLATE utf8mb4_unicode_ci NOT NULL,`dep_id` int(11) NOT NULL, `dest_dep_id` int(11) NOT NULL DEFAULT 0, `sort_priority` int(11) NOT NULL DEFAULT 0,`priority` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `dep_id` (`dep_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); $db->query("CREATE TABLE `lh_canned_msg_dep` (
lhc_web/design/defaulttheme/js/js_static/a07851a85849880a5fd11dd78f238b28.js+1 −1 modifiedlhc_web/design/defaulttheme/js/js_static/a07851a85849880a5fd11dd78f238b28.js.map+1 −1 modifiedlhc_web/design/defaulttheme/js/react/build/all.js+1 −1 modifiedlhc_web/design/defaulttheme/js/react/src/components/builder/NodeTriggerActionCommand.js+53 −23 modified@@ -214,38 +214,68 @@ class NodeTriggerActionCommand extends Component { <input className="form-control form-control-sm" type="text" onChange={(e) => this.onchangeAttr({'path':['payload'],'value':e.target.value})} defaultValue={this.props.action.getIn(['content','payload'])} /> </div> </div> - <div className="col-6"> + + {this.props.action.getIn(['content','payload_arg_type']) != 'count_filter' && this.props.action.getIn(['content','payload_arg_type']) != 'count' && this.props.action.getIn(['content','payload_arg_type']) != 'ratio' && <div className="col-6"> <div className="form-group"> - <label>Chat variable value from group method</label> + <label>Calculated value from group method</label> <input className="form-control form-control-sm" type="text" onChange={(e) => this.onchangeAttr({'path':['payload_cond_field'],'value':e.target.value})} defaultValue={this.props.action.getIn(['content','payload_cond_field'])} /> </div> - </div> - <div className="col-4"> + </div>} + + <div className="col-12"> <div className="form-group"> - <label>Group field (sentiment)</label> - <input className="form-control form-control-sm" type="text" onChange={(e) => this.onchangeAttr({'path':['payload_arg_field'],'value':e.target.value})} defaultValue={this.props.action.getIn(['content','payload_arg_field'])} /> + <label>Group method</label> + <select className="form-control form-control-sm" onChange={(e) => this.onchangeAttr({'path' : ['payload_arg_type'], 'value' : e.target.value})} defaultValue={this.props.action.getIn(['content','payload_arg_type'])}> + <option value="">Select group logic</option> + <optgroup label="Grouping"> + <option value="avg">AVG</option> + <option value="sum">SUM</option> + <option value="sum_avg">SUM as comparator and AVG as value</option> + <option value="max">MAX</option> + <option value="min">MIN</option> + <option value="count_max">COUNT MAX (maximum number of grouped record)</option> + </optgroup> + <optgroup label="Counting"> + <option value="count">COUNT (total number of messages)</option> + <option value="count_filter">COUNT FILTER (filtered by group value field)</option> + <option value="ratio">RATIO in comparison with all messages</option> + </optgroup> + </select> </div> </div> - <div className="col-4"> - <label>Group method</label> - <select className="form-control form-control-sm" onChange={(e) => this.onchangeAttr({'path' : ['payload_arg_type'], 'value' : e.target.value})} defaultValue={this.props.action.getIn(['content','payload_arg_type'])}> - <option value="">Select group logic</option> - <option value="count">COUNT (total number of messages)</option> - <option value="avg">AVG</option> - <option value="sum">SUM</option> - <option value="sum_avg">SUM as comparator and AVG as value</option> - <option value="max">MAX</option> - <option value="min">MIN</option> - <option value="count_max">COUNT MAX (maximum number of grouped record)</option> - <option value="count_filter">COUNT FILTER (filtered by group value field)</option> - </select> - </div> - <div className="col-4"> + + {this.props.action.getIn(['content', 'payload_arg_type']) != 'count' && + <div className="col-6"> + <div className="form-group"> + <label>Group field (sentiment)</label> + <input className="form-control form-control-sm" type="text" + onChange={(e) => this.onchangeAttr({ + 'path': ['payload_arg_field'], + 'value': e.target.value + })} + defaultValue={this.props.action.getIn(['content', 'payload_arg_field'])}/> + </div> + </div> + } + + {this.props.action.getIn(['content','payload_arg_type']) != 'count' && + <div className="col-6"> <div className="form-group"> - <label>Group value field (sentiment_value)</label> + {(this.props.action.getIn(['content','payload_arg_type']) == 'count_filter' || this.props.action.getIn(['content','payload_arg_type']) == 'ratio') && <label>Filter value</label>} + {this.props.action.getIn(['content','payload_arg_type']) != 'count_filter' && this.props.action.getIn(['content','payload_arg_type']) != 'ratio' && <label>Group value field. Eg (score field of the sentiment)</label>} <input className="form-control form-control-sm" type="text" onChange={(e) => this.onchangeAttr({'path':['payload_arg_val'],'value':e.target.value})} defaultValue={this.props.action.getIn(['content','payload_arg_val'])} /> </div> - </div> + </div>} + + { + ['ratio','avg','sum_avg','max','min','count_max'].indexOf(this.props.action.getIn(['content','payload_arg_type'])) !== -1 && + <div className="col-12"> + <div className="form-group"> + <label>Use only if value is one of. If not defined all possible values will be used.</label> + <input className="form-control form-control-sm" placeholder="negative,positive" type="text" onChange={(e) => this.onchangeAttr({'path':['payload_arg_val_sum'],'value':e.target.value})} defaultValue={this.props.action.getIn(['content','payload_arg_val_sum'])} /> + </div> + </div>} + <div className="col-12"> <label>Messages to include</label> <div className="form-group">
lhc_web/design/defaulttheme/tpl/lhchatarchive/viewarchivedchat.tpl.php+12 −1 modified@@ -1,3 +1,9 @@ +<div role="tabpanel" id="tabs"> + <ul class="nav nav-pills" role="tablist"> + </ul> + <div class="tab-content pl-1"> + + <div class="tab-pane active"> <div class="row" ng-non-bindable> <div class="col-sm-7 chat-main-left-column" id="chat-main-column-<?php echo $chat->id;?>"> @@ -33,4 +39,9 @@ <?php include(erLhcoreClassDesign::designtpl('lhchat/chat_tabs/chat_tabs_container.tpl.php')); ?> </div> </div> -<script>ee.emitEvent('adminArchiveChatLoaded', [<?php echo $archive->id?>,<?php echo $chat->id;?>]);</script> \ No newline at end of file +<script>ee.emitEvent('adminArchiveChatLoaded', [<?php echo $archive->id?>,<?php echo $chat->id;?>]);</script> + + </div> + + </div> +</div> \ No newline at end of file
lhc_web/design/defaulttheme/tpl/lhchat/chat_tabs/information_rows/chat.tpl.php+9 −1 modified@@ -1,7 +1,15 @@ <?php if ( $chat->department !== false ) : ?> <tr> <td colspan="2" > - <h6 class="font-weight-bold"><i class="material-icons">chat</i> + <h6 class="font-weight-bold"> + <?php + $icons_additional = erLhAbstractModelChatColumn::getList(array('ignore_fields' => array('position','conditions','column_identifier','enabled'), 'sort' => false, 'filter' => array('icon_mode' => 1, 'enabled' => 1, 'chat_enabled' => 1))); + $chatItems = [$chat]; + erLhcoreClassChat::prefillGetAttributes($chatItems, array(), array(), array('additional_columns' => $icons_additional, 'do_not_clean' => true)); + ?> + <?php include(erLhcoreClassDesign::designtpl('lhchat/lists/icons_additional.tpl.php')); ?> + + <i class="material-icons">chat</i> <?php if ($chat->chat_initiator == erLhcoreClassModelChat::CHAT_INITIATOR_PROACTIVE) : ?> <?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('chat/adminchat','Proactive chat')?> <?php else : ?>
lhc_web/design/defaulttheme/tpl/lhchat/icondetailed.tpl.php+4 −0 added@@ -0,0 +1,4 @@ +<?php $modalHeaderTitle = htmlspecialchars($column->column_name)?> +<?php include(erLhcoreClassDesign::designtpl('lhkernel/modal_header.tpl.php'));?> +<?php echo $column->popup_content?> +<?php include(erLhcoreClassDesign::designtpl('lhkernel/modal_footer.tpl.php'));?>
lhc_web/design/defaulttheme/tpl/lhchat/lists/additional_column_body_online.tpl.php+1 −1 modified@@ -1,3 +1,3 @@ -<td ng-repeat="column in lhc.additionalColumns" ng-if="column.oenabl == true"> +<td ng-repeat="column in lhc.additionalColumns" ng-if="column.oenabl == true && !column.iconm"> <span ng-repeat="val in column.items">{{ou[val]}} </span> </td> \ No newline at end of file
lhc_web/design/defaulttheme/tpl/lhchat/lists/additional_column_body.tpl.php+1 −1 modified@@ -1,3 +1,3 @@ -<td ng-repeat="column in lhc.additionalColumns" ng-if="column.cenabl == true"> +<td ng-repeat="column in lhc.additionalColumns" ng-if="column.cenabl == true && !column.iconm"> <div class="abbr-list" ng-repeat="val in column.items">{{chat[val]}} </div> </td> \ No newline at end of file
lhc_web/design/defaulttheme/tpl/lhchat/lists/additional_column_header.tpl.php+1 −1 modified@@ -1,3 +1,3 @@ -<th width="20%" ng-repeat="column in lhc.additionalColumns" ng-if="column.cenabl == true"> +<th width="20%" ng-repeat="column in lhc.additionalColumns" ng-if="column.cenabl == true && !column.iconm"> <i ng-if="column.icon !== ''" class="material-icons">{{column.icon}}</i>{{column.name}} </th> \ No newline at end of file
lhc_web/design/defaulttheme/tpl/lhchat/lists/icons_additional.tpl.php+9 −0 added@@ -0,0 +1,9 @@ +<?php if (isset($icons_additional) && !empty($icons_additional)) : ?> + <?php foreach ($icons_additional as $iconAdditional) : $columnIconData = json_decode($iconAdditional->column_icon,true); ?> + <?php if (isset($chat->{'cc_' . $iconAdditional->id})) : ?> + <span <?php if ($iconAdditional->has_popup) : ?>onclick="lhc.revealModal({'url':WWW_DIR_JAVASCRIPT + 'chat/icondetailed/' + <?php echo $chat->id?> + '/' + <?php echo $iconAdditional->id?>});"<?php endif;?> class="material-icons<?php if ($iconAdditional->has_popup) : ?> action-image<?php endif; ?>" title="<?php isset($chat->{'cc_' . $iconAdditional->id . '_tt'}) ? print htmlspecialchars($chat->{'cc_' . $iconAdditional->id . '_tt'}) : print htmlspecialchars(isset($chat->{'cc_' . $iconAdditional->id}) ? $chat->{'cc_' . $iconAdditional->id} : '')?>" style="color: <?php echo isset($columnIconData[$chat->{'cc_' . $iconAdditional->id}]['color']) ? htmlspecialchars($columnIconData[$chat->{'cc_' . $iconAdditional->id}]['color']) : '#CECECE'?>"> + <?php $iconAdditional->column_icon != "" && strpos($iconAdditional->column_icon,'"') !== false ? print htmlspecialchars($columnIconData[$chat->{'cc_' . $iconAdditional->id}]['icon']) : print htmlspecialchars($iconAdditional->column_icon); ?> + </span> + <?php endif; ?> + <?php endforeach; ?> +<?php endif; ?> \ No newline at end of file
lhc_web/design/defaulttheme/tpl/lhchat/lists/icon.tpl.php+4 −1 modified@@ -1 +1,4 @@ -<i ng-if="chat.aicons && (lhc.excludeIcons.length == 0 || lhc.excludeIcons.indexOf(icon.i) === -1)" class="material-icons" ng-style="{'color': icon.c ? icon.c : '#6c757d'}" title="{{icon.t ? icon.t : icon.i}}" ng-repeat="icon in chat.aicons track by $index">{{icon.i || icon}}</i> \ No newline at end of file +<i ng-if="chat.aicons && (lhc.excludeIcons.length == 0 || lhc.excludeIcons.indexOf(icon.i) === -1)" class="material-icons" ng-style="{'color': icon.c ? icon.c : '#6c757d'}" title="{{icon.t ? icon.t : icon.i}}" ng-repeat="icon in chat.aicons track by $index">{{icon.i || icon}}</i> +<i ng-repeat="column in lhc.additionalColumns" ng-if="column.cenabl == true && column.iconm == true" > + <span ng-if="chat[val]" ng-click="column.iconp && lhc.openModal('chat/icondetailed/' + chat.id + '/' + column.id, $event)" class="material-icons" title="{{column.iconp == true ? 'Click for more information | ' : ''}}{{chat[val + '_tt'] ? chat[val + '_tt'] : chat[val]}}" style="color: {{column.icon[chat[val]].color}}" ng-repeat="val in column.items">{{column.icon[chat[val]].icon}}</span> +</i> \ No newline at end of file
lhc_web/design/defaulttheme/tpl/lhchat/lists.tpl.php+3 −0 modified@@ -30,6 +30,9 @@ <?php include(erLhcoreClassDesign::designtpl('lhchat/lists/start_row.tpl.php')); ?> <td><?php if ($chat->can_edit_chat == true) : ?><input ng-checked="check_all_items" class="mb-0" type="checkbox" name="ChatID[]" value="<?php echo $chat->id?>" /><?php endif;?></td> <td> + + <?php include(erLhcoreClassDesign::designtpl('lhchat/lists/icons_additional.tpl.php')); ?> + <?php foreach ($chat->aicons as $aicon) : ?> <i class="material-icons" style="color: <?php isset($aicon['c']) ? print htmlspecialchars($aicon['c']) : print '#6c757d'?>" title="<?php isset($aicon['t']) ? print htmlspecialchars($aicon['t']) : htmlspecialchars($aicon['i'])?> {{icon.t ? icon.t : icon.i}}"><?php isset($aicon['i']) ? print htmlspecialchars($aicon['i']) : htmlspecialchars($aicon)?></i> <?php endforeach; ?>
lhc_web/design/defaulttheme/tpl/lhsystem/languages.tpl.php+15 −12 modified@@ -28,12 +28,12 @@ <div class="form-group"> <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Language')?></label> - <select name="language" class="form-control"> + <select name="language" class="form-control form-control-sm"> <?php $userLanguage = erLhcoreClassModelUserSetting::getSetting('user_language', erLhcoreClassSystem::instance()->Language); foreach (erLhcoreClassSiteaccessGenerator::getLanguages() as $language) : ?> - <option value="<?php echo $language['locale']?>" <?php $userLanguage == $language['locale'] ? print 'selected="selected"' : ''?>><?php echo $language['locale']?></option> + <option value="<?php echo htmlspecialchars($language['locale'])?>" <?php $userLanguage == $language['locale'] ? print 'selected="selected"' : ''?>><?php echo htmlspecialchars($language['locale'])?></option> <?php endforeach;?> </select> </div> @@ -49,12 +49,13 @@ <?php if ($currentUser->hasAccessTo('lhsystem','configurelanguages')) : ?> <div role="tabpanel" class="tab-pane <?php if ($tab == 'generalsettings') : ?>active<?php endif;?>" id="generalsettings"> <form action="<?php echo erLhcoreClassDesign::baseurl('system/languages')?>" method="post" name="siteaccess_change"> - <p><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Current site access')?> - <strong><?php echo $current_site_access ?></strong> + <p><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Current site access')?> - <strong><?php echo htmlspecialchars($current_site_access) ?></strong> </p> - <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Site access')?></label> <select id="LocaleID" name="siteaccess" onchange="document.siteaccess_change.submit()" class="form-control"> + <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Site access')?></label> + <select id="LocaleID" name="siteaccess" onchange="document.siteaccess_change.submit()" class="form-control form-control-sm"> <?php foreach ($locales as $locale) : ?> - <option value="<?php echo $locale?>" <?php $input->siteaccess == $locale ? print 'selected="selected"' : ''?>><?php echo $locale?></option> + <option value="<?php echo htmlspecialchars($locale)?>" <?php $input->siteaccess == $locale ? print 'selected="selected"' : ''?>><?php echo htmlspecialchars($locale)?></option> <?php endforeach; ?> </select> @@ -68,7 +69,7 @@ <?php include(erLhcoreClassDesign::designtpl('lhkernel/csfr_token.tpl.php'));?> - <input type="hidden" name="siteaccess" value="<?php echo $input->siteaccess?>" /> + <input type="hidden" name="siteaccess" value="<?php echo htmlspecialchars($input->siteaccess)?>" /> <?php $siteAccessOptions = erConfigClassLhConfig::getInstance()->getSetting( 'site_access_options', $input->siteaccess ); @@ -77,24 +78,26 @@ <div class="form-group"> <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Language')?></label> - <select name="language" class="form-control"> + <select name="language" class="form-control form-control-sm"> <?php foreach (erLhcoreClassSiteaccessGenerator::getLanguages() as $language) : ?> - <option value="<?php echo $language['locale']?>" <?php $siteAccessOptions['locale'] == $language['locale'] ? print 'selected="selected"' : ''?>><?php echo $language['locale']?></option> + <option value="<?php echo htmlspecialchars($language['locale'])?>" <?php $siteAccessOptions['locale'] == $language['locale'] ? print 'selected="selected"' : ''?>><?php echo htmlspecialchars($language['locale'])?></option> <?php endforeach;?> </select> </div> <div class="form-group"> <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Theme, separate themes by new line')?></label> - <textarea class="form-control" name="theme"><?php echo implode("\n", $siteAccessOptions['theme'])?></textarea> + <textarea class="form-control form-control-sm" name="theme"><?php echo htmlspecialchars(implode("\n", $siteAccessOptions['theme']))?></textarea> </div> <div class="row form-group"> <div class="col-md-3"> - <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Default module')?></label> <input type="text" class="form-control" name="module" value="<?php echo $siteAccessOptions['default_url']['module']?>" /> + <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Default module')?></label> + <input type="text" class="form-control form-control-sm" name="module" value="<?php echo htmlspecialchars($siteAccessOptions['default_url']['module'])?>" /> </div> <div class="col-md-3"> - <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Default view')?></label> <input type="text" class="form-control" name="view" value="<?php echo $siteAccessOptions['default_url']['view']?>" /> + <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Default view')?></label> + <input type="text" class="form-control form-control-sm" name="view" value="<?php echo htmlspecialchars($siteAccessOptions['default_url']['view'])?>" /> </div> </div> @@ -103,7 +106,7 @@ </form> </div> - <?php endif;?> + <?php endif;?> </div> </div> \ No newline at end of file
lhc_web/design/defaulttheme/tpl/lhviews/loadview.tpl.php+3 −0 modified@@ -27,6 +27,9 @@ <?php foreach ($items as $chat) : ?> <?php include(erLhcoreClassDesign::designtpl('lhchat/lists/start_row.tpl.php')); ?> <td nowrap=""> + + <?php include(erLhcoreClassDesign::designtpl('lhchat/lists/icons_additional.tpl.php')); ?> + <?php foreach ($chat->aicons as $aicon) : ?> <i class="material-icons" style="color: <?php isset($aicon['c']) ? print htmlspecialchars($aicon['c']) : print '#6c757d'?>" title="<?php isset($aicon['t']) ? print htmlspecialchars($aicon['t']) : htmlspecialchars($aicon['i'])?> {{icon.t ? icon.t : icon.i}}"><?php isset($aicon['i']) ? print htmlspecialchars($aicon['i']) : htmlspecialchars($aicon)?></i> <?php endforeach; ?>
lhc_web/doc/CHANGELOG.txt+8 −0 modified@@ -1,3 +1,11 @@ +3.99v + +1. Message aggregation for sentiment analysis per message implementation. +2. Small security fix +3. + +execute doc/update_db/update_271.sql for update + 3.98v 1. Option to share your views with other operators.
lhc_web/doc/update_db/structure.json+25 −0 modified@@ -5540,6 +5540,31 @@ "default": null, "extra": "" }, + { + "field": "icon_mode", + "type": "tinyint(1)", + "null": "NO", + "key": "", + "default": "0", + "extra": "" + }, + { + "field": "has_popup", + "type": "tinyint(1)", + "null": "NO", + "key": "", + "default": "0", + "extra": "" + }, + { + "field": "popup_content", + "type": "longtext", + "null": "NO", + "key": "", + "default": null, + "extra": "", + "collation": "utf8mb4_unicode_ci" + }, { "field": "online_enabled", "type": "tinyint(1)",
lhc_web/doc/update_db/update_271.sql+3 −0 added@@ -0,0 +1,3 @@ +ALTER TABLE `lh_abstract_chat_column` ADD `icon_mode` tinyint(1) NOT NULL DEFAULT '0', COMMENT=''; +ALTER TABLE `lh_abstract_chat_column` ADD `has_popup` tinyint(1) NOT NULL DEFAULT '0', COMMENT=''; +ALTER TABLE `lh_abstract_chat_column` ADD `popup_content` longtext NOT NULL, COMMENT=''; \ No newline at end of file
lhc_web/lib/core/lhabstract/fields/erlhabstractmodelchatcolumn.php+22 −0 modified@@ -40,6 +40,13 @@ 'hide_optional' => true, 'validation_definition' => new ezcInputFormDefinitionElement(ezcInputFormDefinitionElement::OPTIONAL, 'boolean') ), + 'icon_mode' => array( + 'type' => 'checkbox', + 'trans' => erTranslationClassLhTranslation::getInstance()->getTranslation('abstract/proactivechatinvitation', 'Icon mode'), + 'required' => false, + 'hide_optional' => true, + 'validation_definition' => new ezcInputFormDefinitionElement(ezcInputFormDefinitionElement::OPTIONAL, 'boolean') + ), 'chat_enabled' => array( 'type' => 'checkbox', 'trans' => erTranslationClassLhTranslation::getInstance()->getTranslation('abstract/proactivechatinvitation', 'Visible in chat list'), @@ -48,6 +55,21 @@ 'hide_optional' => true, 'validation_definition' => new ezcInputFormDefinitionElement(ezcInputFormDefinitionElement::OPTIONAL, 'boolean') ), + 'has_popup' => array( + 'type' => 'checkbox', + 'trans' => erTranslationClassLhTranslation::getInstance()->getTranslation('abstract/proactivechatinvitation', 'Has popup information'), + 'hidden' => true, + 'required' => false, + 'hide_optional' => true, + 'validation_definition' => new ezcInputFormDefinitionElement(ezcInputFormDefinitionElement::OPTIONAL, 'boolean') + ), + 'popup_content' => array( + 'type' => 'textarea', + 'trans' => erTranslationClassLhTranslation::getInstance()->getTranslation('abstract/email_template','Popup content, icon will have an option to show a modal window'), + 'required' => false, + 'validation_definition' => new ezcInputFormDefinitionElement( + ezcInputFormDefinitionElement::OPTIONAL, 'unsafe_raw' + )), 'online_enabled' => array( 'type' => 'checkbox', 'trans' => erTranslationClassLhTranslation::getInstance()->getTranslation('abstract/proactivechatinvitation', 'Visible in online visitors list'),
lhc_web/lib/core/lhabstract/lhabstract.php+13 −4 modified@@ -48,7 +48,9 @@ public static function renderInput($name, $attr, $object, $defaultValue = '') $ngModel .= " maxlength=\"{$attr['maxlength']}\" "; } - return '<input class="form-control form-control-sm' . (isset($attr['css_class']) ? ' ' . $attr['css_class'] : '') . '" ' . $ngModel . ' name="AbstractInput_' . $name . '" type="' . $attr['type'] . '" value="' . htmlspecialchars($value) . '" />'; + $nameInputPrepend = (isset($attr['direct_name']) && $attr['direct_name'] == true) ? '' : 'AbstractInput_'; + + return '<input class="form-control form-control-sm' . (isset($attr['css_class']) ? ' ' . $attr['css_class'] : '') . '" ' . $ngModel . ' name="' . $nameInputPrepend . $name . '" type="' . $attr['type'] . '" value="' . htmlspecialchars($value) . '" />'; } break; @@ -153,13 +155,20 @@ public static function renderInput($name, $attr, $object, $defaultValue = '') case 'combobox': $onchange = isset($attr['on_change']) ? $attr['on_change'] : ''; - $return = '<select ng-non-bindable class="form-control form-control-sm" name="AbstractInput_' . $name . '"' . $onchange . '>'; + $nameInputPrepend = (isset($attr['direct_name']) && $attr['direct_name'] == true) ? '' : 'AbstractInput_'; + + $return = '<select ng-non-bindable class="form-control form-control-sm" name="' . $nameInputPrepend . $name . '"' . $onchange . '>'; if (!isset($attr['hide_optional']) || $attr['hide_optional'] == false) { - $return .= '<option value="0">Choose option</option>'; + $optionalValue = isset($attr['optional_value']) ? $attr['optional_value'] : 0; + $return .= '<option value="' . $optionalValue . '">' . erTranslationClassLhTranslation::getInstance()->getTranslation('chat/lists/search_panel','Choose') . '</option>'; } - $items = call_user_func($attr['source'], $attr['params_call']); + if ($attr['source'] instanceof Closure) { + $items = $attr['source'](); + } else { + $items = call_user_func($attr['source'], $attr['params_call']); + } if (isset($attr['main_attr']) && !empty($attr['main_attr'])) { if (isset($object->{$attr['main_attr']}[$name])) {
lhc_web/lib/core/lhchat/lhchat.php+7 −1 modified@@ -1593,7 +1593,14 @@ public static function prefillGetAttributes(& $objects, $attrs = array(),$attrRe }; if (isset($params['additional_columns']) && is_array($params['additional_columns']) && !empty($params['additional_columns'])) { + foreach ($params['additional_columns'] as $column) { + + // Translatable title + if (strpos($column->column_name,'{args.') !== false) { + $object->{'cc_' . $column->id . '_tt'} = erLhcoreClassGenericBotWorkflow::translateMessage($column->column_name, array('chat' => $object, 'args' => ['chat' => $object])); + } + if (strpos($column->variable,'additional_data.') !== false) { $additionalDataArray = $object->additional_data_array; if (is_array($additionalDataArray)) { @@ -1633,7 +1640,6 @@ public static function prefillGetAttributes(& $objects, $attrs = array(),$attrRe } } - foreach ($attrRemove as $attr) { $object->{$attr} = null; if (isset($params['clean_ignore'])) {
lhc_web/lib/core/lhcore/lhupdate.php+3 −3 modified@@ -2,8 +2,8 @@ class erLhcoreClassUpdate { - const DB_VERSION = 270; - const LHC_RELEASE = 398; + const DB_VERSION = 271; + const LHC_RELEASE = 399; public static function doTablesUpdate($definition){ $updateInformation = self::getTablesStatus($definition); @@ -12,7 +12,7 @@ public static function doTablesUpdate($definition){ $errorMessages = array(); try { - $db->query('SET GLOBAL innodb_strict_mode = 0;'); + $db->query('SET GLOBAL innodb_strict_mode=0;'); $db->query('SET GLOBAL innodb_file_per_table=1;'); $db->query('SET GLOBAL innodb_large_prefix=1;'); } catch (Exception $e) {
lhc_web/lib/core/lhgenericbot/actionTypes/lhgenericbotactioncommand.php+40 −8 modified@@ -288,9 +288,6 @@ public static function process($chat, $action, $trigger, $params) if ( !isset($messages) || (!isset($action['content']['payload']) || empty($action['content']['payload'])) || - (!isset($action['content']['payload_cond_field']) || empty($action['content']['payload_cond_field'])) || - (!isset($action['content']['payload_arg_field']) || empty($action['content']['payload_arg_field'])) || - (!isset($action['content']['payload_arg_val']) || empty($action['content']['payload_arg_val'])) || (!isset($action['content']['payload_arg_type']) || empty($action['content']['payload_arg_type'])) ) { return; @@ -314,16 +311,16 @@ public static function process($chat, $action, $trigger, $params) $chatVariableName = $action['content']['payload']; // Group value field (sentiment_value) - $chatVariableValue = $action['content']['payload_cond_field']; + $chatVariableValue = isset($action['content']['payload_cond_field']) ? $action['content']['payload_cond_field'] : ''; /* * Messages attributes * */ // Group field (sentiment) - $messagesGroupField = $action['content']['payload_arg_field']; + $messagesGroupField = isset($action['content']['payload_arg_field']) ? $action['content']['payload_arg_field'] : ''; // Group value field (sentiment_value) - $messagesGroupFieldValue = $action['content']['payload_arg_val']; + $messagesGroupFieldValue = isset($action['content']['payload_arg_val']) ? $action['content']['payload_arg_val'] : ''; // Group method $groupMethod = $action['content']['payload_arg_type']; @@ -332,12 +329,41 @@ public static function process($chat, $action, $trigger, $params) if ($groupMethod == 'count') { $variablesArray[$chatVariableName] = count($messages); + } else if ($groupMethod == 'ratio') { + + if (!isset($action['content']['payload_arg_val_sum'])){ + return; + } + + $messagesGroupFieldAll = $action['content']['payload_arg_val_sum']; + + $counterTotal = 0; + $counterRequired = 0; + foreach ($messages as $message) { + $messageVariables = $message->meta_msg_array; + + if (isset($messageVariables[$messagesGroupField]) && in_array($messageVariables[$messagesGroupField],explode(',',$messagesGroupFieldValue))) { + $counterRequired++; + } + + if (isset($messageVariables[$messagesGroupField]) && in_array($messageVariables[$messagesGroupField],explode(',',$messagesGroupFieldAll))) { + $counterTotal++; + } + } + + if ($counterTotal > 0) { + $variablesArray[$chatVariableName] = round($counterRequired/$counterTotal,4); + $chat->chat_variables = json_encode($variablesArray); + $chat->chat_variables_array = $variablesArray; + $chat->updateThis(['update' => ['chat_variables']]); + } + } else if ($groupMethod == 'count_filter') { $counter = 0; foreach ($messages as $message) { $messageVariables = $message->meta_msg_array; - if (isset($messageVariables[$messagesGroupField]) && $messageVariables[$messagesGroupField] == $messagesGroupFieldValue) { + if (isset($messageVariables[$messagesGroupField]) && in_array($messageVariables[$messagesGroupField],explode(',',$messagesGroupFieldValue))) { $counter++; } } @@ -351,13 +377,19 @@ public static function process($chat, $action, $trigger, $params) $groupedFields = []; + $messagesGroupFieldAll = isset($action['content']['payload_arg_val_sum']) ? explode(',',$action['content']['payload_arg_val_sum']) : []; + foreach ($messages as $message) { $messageVariables = $message->meta_msg_array; if (isset($messageVariables[$messagesGroupField])) { - $groupedFields[$messageVariables[$messagesGroupField]][] = $messageVariables[$messagesGroupFieldValue]; + if (empty($messagesGroupFieldAll) || in_array($messageVariables[$messagesGroupField],$messagesGroupFieldAll)){ + $groupedFields[$messageVariables[$messagesGroupField]][] = $messageVariables[$messagesGroupFieldValue]; + } } } + + $highestScore = 0; foreach ($groupedFields as $sentiment => $values) {
lhc_web/lib/core/lhpermission/lhmodules.php+25 −0 modified@@ -45,6 +45,31 @@ public static function getModuleList() return $ModuleList ; } + public static function getViewsByModule($ModulePath) + { + $ViewListProcessed = []; + if (file_exists('modules/' . $ModulePath . '/module.php')) { + include('modules/' . $ModulePath . '/module.php'); + if (isset($ViewList) && !empty($ViewList)) { + $ViewListProcessed = array_merge($ViewListProcessed, array_keys($ViewList)); + } + } + $cfg = erConfigClassLhConfig::getInstance(); + // Append Override functions + $extensions = $cfg->getSetting( 'site', 'extensions' ); + foreach ($extensions as $extension) { + if (file_exists("extension/{$extension}/modules/{$ModulePath}/module.php")) { + $ViewList = []; + include("extension/{$extension}/modules/{$ModulePath}/module.php"); + if (isset($ViewList) && !empty($ViewList)) { + $ViewListProcessed = array_merge($ViewListProcessed, array_keys($ViewList)); + } + } + } + + return $ViewListProcessed; + } + public static function getModuleFunctions($ModulePath, $params = array()) { $FunctionListReturn = array();
lhc_web/lib/models/lhabstract/erlhabstractmodelchatcolumn.php+6 −10 modified@@ -25,6 +25,9 @@ public function getState() 'column_identifier' => $this->column_identifier, 'chat_enabled' => $this->chat_enabled, 'online_enabled' => $this->online_enabled, + 'icon_mode' => $this->icon_mode, + 'has_popup' => $this->has_popup, + 'popup_content' => $this->popup_content, ); return $stateArray; @@ -77,25 +80,18 @@ public function __get($var) } public $id = null; - public $column_name = ''; - public $column_icon = ''; - public $column_identifier = ''; - public $variable = ''; - public $position = ''; - public $enabled = 1; - public $conditions = ''; - + public $popup_content = ''; public $chat_enabled = 1; - public $online_enabled = 1; - + public $icon_mode = 0; + public $has_popup = 0; public $hide_delete = false; }
lhc_web/modules/lhchatarchive/viewarchivedchat.php+2 −0 modified@@ -17,6 +17,7 @@ } $Result['content'] = $tpl->fetch(); +$Result['body_class'] = 'h-100 dashboard-height'; $Result['path'] = array( array('url' => erLhcoreClassDesign::baseurl('system/configuration'),'title' => erTranslationClassLhTranslation::getInstance()->getTranslation('department/departments','System configuration')), @@ -26,4 +27,5 @@ $Result['path'][] = array('title' => erTranslationClassLhTranslation::getInstance()->getTranslation('chatarchive/viewarchivedchat','View archived chat')); + ?> \ No newline at end of file
lhc_web/modules/lhchat/icondetailed.php+20 −0 added@@ -0,0 +1,20 @@ +<?php + +$tpl = erLhcoreClassTemplate::getInstance('lhchat/icondetailed.tpl.php'); + +$chat = erLhcoreClassModelChat::fetch($Params['user_parameters']['chat_id']); +$column = erLhAbstractModelChatColumn::fetch($Params['user_parameters']['column_id']); + +if ( erLhcoreClassChat::hasAccessToRead($chat) ) { + $column->column_name = erLhcoreClassGenericBotWorkflow::translateMessage($column->column_name, array('chat' => $chat, 'args' => ['chat' => $chat])); + $column->popup_content = erLhcoreClassGenericBotWorkflow::translateMessage($column->popup_content, array('chat' => $chat, 'args' => ['chat' => $chat])); + $tpl->set('column',$column); + $tpl->set('chat',$chat); +} else { + $tpl->setFile( 'lhchat/errors/adminchatnopermission.tpl.php'); +} + +echo $tpl->fetch(); +exit; + +?> \ No newline at end of file
lhc_web/modules/lhchat/list.php+3 −0 modified@@ -165,6 +165,9 @@ if ($pages->items_total > 0) { $items = erLhcoreClassModelChat::getList(array_merge($filterParams['filter'],array('limit' => $pages->items_per_page,'offset' => $pages->low))); + $iconsAdditional = erLhAbstractModelChatColumn::getList(array('ignore_fields' => array('position','conditions','column_identifier','enabled'), 'sort' => false, 'filter' => array('icon_mode' => 1, 'enabled' => 1, 'chat_enabled' => 1))); + erLhcoreClassChat::prefillGetAttributes($items, array(), array(), array('additional_columns' => $iconsAdditional, 'do_not_clean' => true)); + $tpl->set('icons_additional',$iconsAdditional); erLhcoreClassChatEventDispatcher::getInstance()->dispatch('chat.list_items',array('filter' => & $items, 'uparams' => $Params['user_parameters_unordered'])); $tpl->set('items',$items); }
lhc_web/modules/lhchat/loadinitialdata.php+7 −2 modified@@ -153,15 +153,20 @@ } } -$columns = erLhAbstractModelChatColumn::getList(array('ignore_fields' => array('position','conditions','enabled','variable'), 'sort' => 'position ASC, id ASC','filter' => array('enabled' => 1))); +$columns = erLhAbstractModelChatColumn::getList(array('ignore_fields' => array('popup_content','position','conditions','enabled','variable'), 'sort' => 'position ASC, id ASC','filter' => array('enabled' => 1))); $columnsAdd = array(); foreach ($columns as $column) { $columnsAdd[$column->column_identifier]['items'][] = 'cc_' . $column->id; $columnsAdd[$column->column_identifier]['name'] = $column->column_name; - $columnsAdd[$column->column_identifier]['icon'] = $column->column_icon; + $columnsAdd[$column->column_identifier]['icon'] = $column->column_icon != "" && strpos($column->column_icon,'"') !== false ? json_decode($column->column_icon,true) : $column->column_icon; $columnsAdd[$column->column_identifier]['cenabl'] = $column->chat_enabled == 1; $columnsAdd[$column->column_identifier]['oenabl'] = $column->online_enabled == 1; + $columnsAdd[$column->column_identifier]['iconm'] = $column->icon_mode == 1; + $columnsAdd[$column->column_identifier]['iconp'] = $column->has_popup == 1; + if ($columnsAdd[$column->column_identifier]['iconp'] === true) { + $columnsAdd[$column->column_identifier]['id'] = $column->id; + } } $groupListParams = erLhcoreClassGroupUser::getConditionalUserFilter(false, true);
lhc_web/modules/lhchat/module.php+6 −0 modified@@ -17,6 +17,12 @@ 'functions' => array( 'use' ), ); +$ViewList['icondetailed'] = array( + 'params' => array('chat_id','column_id'), + 'uparams' => array(), + 'functions' => array( 'use' ), +); + $ViewList['chathistory'] = array( 'params' => array('chat_id'), 'uparams' => array(),
lhc_web/modules/lhchat/syncadmininterface.php+1 −1 modified@@ -31,7 +31,7 @@ // We do not need a session anymore session_write_close(); -$columnsAdditional = erLhAbstractModelChatColumn::getList(array('ignore_fields' => array('position','conditions','column_name','column_name','column_identifier','enabled'), 'sort' => false, 'filter' => array('enabled' => 1, 'chat_enabled' => 1))); +$columnsAdditional = erLhAbstractModelChatColumn::getList(array('ignore_fields' => array('position','conditions','column_identifier','enabled','popup_content','has_popup','icon_mode','online_enabled','column_icon'), 'sort' => false, 'filter' => array('enabled' => 1, 'chat_enabled' => 1))); // User has included custom column which we ignore by default foreach ($columnsAdditional as $columnAdditional) {
lhc_web/modules/lhcron/test.php+3 −0 modified@@ -6,4 +6,7 @@ * * */ +$chat = erLhcoreClassModelChat::fetch( 1647599587); +erLhcoreClassChatEventDispatcher::getInstance()->dispatch('chat.close',array('chat' => & $chat)); + ?> \ No newline at end of file
lhc_web/modules/lhinstall/install.php+1 −1 modified@@ -2103,7 +2103,7 @@ $db->query("CREATE TABLE `lh_incoming_webhook` ( `id` int(11) NOT NULL AUTO_INCREMENT, `dep_id` int(11) NOT NULL, `name` varchar(50) NOT NULL,`identifier` varchar(50) NOT NULL, `scope` varchar(50) NOT NULL, `disabled` tinyint(1) NOT NULL, `configuration` longtext NOT NULL, PRIMARY KEY (`id`), KEY `identifier` (`identifier`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); $db->query("CREATE TABLE `lh_chat_incoming` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `chat_id` bigint(20) NOT NULL, `utime` bigint(20) NOT NULL, `incoming_id` int(11) NOT NULL,`payload` longtext NOT NULL, `chat_external_id` varchar(50) NOT NULL, PRIMARY KEY (`id`), KEY `chat_id` (`chat_id`), KEY `incoming_ext_id` (`incoming_id`,`chat_external_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); - $db->query("CREATE TABLE `lh_abstract_chat_column` (`id` int(11) NOT NULL AUTO_INCREMENT,`column_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,`variable` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `position` int(11) NOT NULL, `enabled` tinyint(1) NOT NULL, `online_enabled` tinyint(1) NOT NULL, `chat_enabled` tinyint(1) NOT NULL, `conditions` text COLLATE utf8mb4_unicode_ci NOT NULL,`column_icon` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `column_identifier` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`id`), KEY `enabled` (`enabled`), KEY `online_enabled` (`online_enabled`), KEY `chat_enabled` (`chat_enabled`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); + $db->query("CREATE TABLE `lh_abstract_chat_column` (`id` int(11) NOT NULL AUTO_INCREMENT,`column_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `has_popup` tinyint(1) NOT NULL DEFAULT 0, `popup_content` longtext COLLATE utf8mb4_unicode_ci NOT NULL, `variable` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `position` int(11) NOT NULL, `enabled` tinyint(1) NOT NULL, `online_enabled` tinyint(1) NOT NULL, `icon_mode` tinyint(1) NOT NULL DEFAULT 0, `chat_enabled` tinyint(1) NOT NULL, `conditions` text COLLATE utf8mb4_unicode_ci NOT NULL,`column_icon` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `column_identifier` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`id`), KEY `enabled` (`enabled`), KEY `online_enabled` (`online_enabled`), KEY `chat_enabled` (`chat_enabled`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); $db->query("CREATE TABLE `lh_abstract_chat_priority` (`id` int(11) NOT NULL AUTO_INCREMENT,`value` text COLLATE utf8mb4_unicode_ci NOT NULL,`dep_id` int(11) NOT NULL, `dest_dep_id` int(11) NOT NULL DEFAULT 0, `sort_priority` int(11) NOT NULL DEFAULT 0,`priority` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `dep_id` (`dep_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); $db->query("CREATE TABLE `lh_canned_msg_use` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `canned_id` int(11) unsigned NOT NULL, `chat_id` bigint(20) unsigned NOT NULL, `ctime` bigint(20) unsigned NOT NULL, `user_id` bigint(20) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `ctime` (`ctime`), KEY `chat_id` (`chat_id`), KEY `canned_id` (`canned_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;");
lhc_web/modules/lhsystem/languages.php+31 −9 modified@@ -20,6 +20,14 @@ $tab = 'generalsettings'; } +$cfgSite = erConfigClassLhConfig::getInstance(); +$siteAccessAvailable = $cfgSite->getSetting( 'site', 'available_site_access' ); + +if (!in_array($input->siteaccess, $siteAccessAvailable)) { + erLhcoreClassModule::redirect('system/languages'); + exit; +} + if ( isset($_POST['StoreUserSettingsAction']) ) { $definition = array( 'language' => new ezcInputFormDefinitionElement( @@ -37,7 +45,12 @@ $form = new ezcInputForm( INPUT_POST, $definition ); $Errors = array(); - if ( $form->hasValidData( 'language' ) && !empty($form->language)) { + $languagesValid = []; + foreach (erLhcoreClassSiteaccessGenerator::getLanguages() as $language) { + $languagesValid[] = $language['locale']; + } + + if ( $form->hasValidData( 'language' ) && !empty($form->language) && in_array($form->language,$languagesValid)) { erLhcoreClassModelUserSetting::setSetting('user_language',$form->language); // Redirect for change to take effect @@ -80,27 +93,36 @@ $form = new ezcInputForm( INPUT_POST, $definition ); $Errors = array(); - if ( $form->hasValidData( 'siteaccess' )) { + if ($form->hasValidData( 'siteaccess' ) && in_array($input->siteaccess, $siteAccessAvailable)) { $input->siteaccess = $form->siteaccess; - } + } else { + $Errors[] = erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Please choose a valid siteaccess'); + } + + $languagesValid = []; + foreach (erLhcoreClassSiteaccessGenerator::getLanguages() as $language) { + $languagesValid[] = $language['locale']; + } - if ( $form->hasValidData( 'language' )) { + if ( $form->hasValidData( 'language' ) && in_array($form->language,$languagesValid)) { $input->language = $form->language; - } + } else { + $Errors[] = erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Please choose a language'); + } if ( $form->hasValidData( 'theme' ) && $form->theme != '') { $input->theme = $form->theme; } else { $Errors[] = erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Please enter theme'); } - if ( $form->hasValidData( 'module' ) && $form->module != '') { + if ( $form->hasValidData( 'module' ) && $form->module != '' && in_array('lh'.$form->module,array_keys(erLhcoreClassModules::getModuleList()))) { $input->module = $form->module; } else { $Errors[] = erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Please enter module name'); } - if ( $form->hasValidData( 'view' ) && $form->view != '') { + if (empty($Errors) && $form->hasValidData( 'view' ) && $form->view != '' && in_array($form->view,erLhcoreClassModules::getViewsByModule('lh'.$form->module))) { $input->view = $form->view; } else { $Errors[] = erTranslationClassLhTranslation::getInstance()->getTranslation('system/languages','Please enter view name'); @@ -129,8 +151,8 @@ } } -$cfgSite = erConfigClassLhConfig::getInstance(); -$tpl->set('locales',$cfgSite->getSetting( 'site', 'available_site_access' )); + +$tpl->set('locales',$siteAccessAvailable); $tpl->set('current_site_access',erLhcoreClassSystem::instance()->SiteAccess); $tpl->set('input',$input); $tpl->set('currentUser',$currentUser);
lhc_web/modules/lhviews/loadview.php+3 −0 modified@@ -33,6 +33,9 @@ $tpl->set('pages',$pages); $filter = array_merge_recursive($filterSearch, array('limit' => $pages->items_per_page, 'offset' => $pages->low)); $items = erLhcoreClassModelChat::getList($filter); + $iconsAdditional = erLhAbstractModelChatColumn::getList(array('ignore_fields' => array('position','conditions','column_identifier','enabled'), 'sort' => false, 'filter' => array('icon_mode' => 1, 'enabled' => 1, 'chat_enabled' => 1))); + erLhcoreClassChat::prefillGetAttributes($items, array(), array(), array('additional_columns' => $iconsAdditional, 'do_not_clean' => true)); + $tpl->set('icons_additional',$iconsAdditional); $tpl->set('items', $items); $tpl->set('list_mode', $Params['user_parameters_unordered']['mode'] == 'list');
lhc_web/pos/lhabstract/erlhabstractmodelautoresponder.php+31 −182 modified@@ -9,105 +9,29 @@ $def->idProperty->propertyName = 'id'; $def->idProperty->generator = new ezcPersistentGeneratorDefinition( 'ezcPersistentNativeGenerator' ); -$def->properties['name'] = new ezcPersistentObjectProperty(); -$def->properties['name']->columnName = 'name'; -$def->properties['name']->propertyName = 'name'; -$def->properties['name']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['operator'] = new ezcPersistentObjectProperty(); -$def->properties['operator']->columnName = 'operator'; -$def->properties['operator']->propertyName = 'operator'; -$def->properties['operator']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['siteaccess'] = new ezcPersistentObjectProperty(); -$def->properties['siteaccess']->columnName = 'siteaccess'; -$def->properties['siteaccess']->propertyName = 'siteaccess'; -$def->properties['siteaccess']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['languages'] = new ezcPersistentObjectProperty(); -$def->properties['languages']->columnName = 'languages'; -$def->properties['languages']->propertyName = 'languages'; -$def->properties['languages']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['wait_message'] = new ezcPersistentObjectProperty(); -$def->properties['wait_message']->columnName = 'wait_message'; -$def->properties['wait_message']->propertyName = 'wait_message'; -$def->properties['wait_message']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -// This applies only to proactive chats -$def->properties['only_proactive'] = new ezcPersistentObjectProperty(); -$def->properties['only_proactive']->columnName = 'only_proactive'; -$def->properties['only_proactive']->propertyName = 'only_proactive'; -$def->properties['only_proactive']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -// Timeout in seconds. -$def->properties['wait_timeout'] = new ezcPersistentObjectProperty(); -$def->properties['wait_timeout']->columnName = 'wait_timeout'; -$def->properties['wait_timeout']->propertyName = 'wait_timeout'; -$def->properties['wait_timeout']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['wait_timeout_2'] = new ezcPersistentObjectProperty(); -$def->properties['wait_timeout_2']->columnName = 'wait_timeout_2'; -$def->properties['wait_timeout_2']->propertyName = 'wait_timeout_2'; -$def->properties['wait_timeout_2']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['wait_timeout_3'] = new ezcPersistentObjectProperty(); -$def->properties['wait_timeout_3']->columnName = 'wait_timeout_3'; -$def->properties['wait_timeout_3']->propertyName = 'wait_timeout_3'; -$def->properties['wait_timeout_3']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['wait_timeout_4'] = new ezcPersistentObjectProperty(); -$def->properties['wait_timeout_4']->columnName = 'wait_timeout_4'; -$def->properties['wait_timeout_4']->propertyName = 'wait_timeout_4'; -$def->properties['wait_timeout_4']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['wait_timeout_5'] = new ezcPersistentObjectProperty(); -$def->properties['wait_timeout_5']->columnName = 'wait_timeout_5'; -$def->properties['wait_timeout_5']->propertyName = 'wait_timeout_5'; -$def->properties['wait_timeout_5']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -// Department ID -$def->properties['dep_id'] = new ezcPersistentObjectProperty(); -$def->properties['dep_id']->columnName = 'dep_id'; -$def->properties['dep_id']->propertyName = 'dep_id'; -$def->properties['dep_id']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -// Position -$def->properties['position'] = new ezcPersistentObjectProperty(); -$def->properties['position']->columnName = 'position'; -$def->properties['position']->propertyName = 'position'; -$def->properties['position']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -// Then timeout passes show visitor this message. -$def->properties['timeout_message'] = new ezcPersistentObjectProperty(); -$def->properties['timeout_message']->columnName = 'timeout_message'; -$def->properties['timeout_message']->propertyName = 'timeout_message'; -$def->properties['timeout_message']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['timeout_message_2'] = new ezcPersistentObjectProperty(); -$def->properties['timeout_message_2']->columnName = 'timeout_message_2'; -$def->properties['timeout_message_2']->propertyName = 'timeout_message_2'; -$def->properties['timeout_message_2']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['timeout_message_3'] = new ezcPersistentObjectProperty(); -$def->properties['timeout_message_3']->columnName = 'timeout_message_3'; -$def->properties['timeout_message_3']->propertyName = 'timeout_message_3'; -$def->properties['timeout_message_3']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['timeout_message_4'] = new ezcPersistentObjectProperty(); -$def->properties['timeout_message_4']->columnName = 'timeout_message_4'; -$def->properties['timeout_message_4']->propertyName = 'timeout_message_4'; -$def->properties['timeout_message_4']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['timeout_message_5'] = new ezcPersistentObjectProperty(); -$def->properties['timeout_message_5']->columnName = 'timeout_message_5'; -$def->properties['timeout_message_5']->propertyName = 'timeout_message_5'; -$def->properties['timeout_message_5']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; +foreach (['name','operator','siteaccess','languages','wait_message','timeout_message','timeout_message_2','timeout_message_3','timeout_message_4','timeout_message_5','wait_timeout_hold','bot_configuration'] as $posAttr) { + $def->properties[$posAttr] = new ezcPersistentObjectProperty(); + $def->properties[$posAttr]->columnName = $posAttr; + $def->properties[$posAttr]->propertyName = $posAttr; + $def->properties[$posAttr]->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; +} -$def->properties['wait_timeout_hold'] = new ezcPersistentObjectProperty(); -$def->properties['wait_timeout_hold']->columnName = 'wait_timeout_hold'; -$def->properties['wait_timeout_hold']->propertyName = 'wait_timeout_hold'; -$def->properties['wait_timeout_hold']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; +// only_proactive - This applies only to proactive chats +// wait_timeout - Timeout in seconds. +// How many times repeat timeout message - repeat_number +// 0 - infinity times +// 1 - one time +// ignore_pa_chat - // Ignore pending and assigned chat. +// Pending messages won't be send if chat is assigned +foreach (['only_proactive','wait_timeout','wait_timeout_2','wait_timeout_3', + 'wait_timeout_4','wait_timeout_5', + 'dep_id','position','repeat_number','ignore_pa_chat', + 'survey_timeout','survey_id','user_id'] as $posAttr) { + $def->properties[$posAttr] = new ezcPersistentObjectProperty(); + $def->properties[$posAttr]->columnName = $posAttr; + $def->properties[$posAttr]->propertyName = $posAttr; + $def->properties[$posAttr]->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; +} for ($i = 1; $i <= 5; $i++) { $def->properties['wait_timeout_hold_' . $i] = new ezcPersistentObjectProperty(); @@ -119,92 +43,17 @@ $def->properties['timeout_hold_message_' . $i]->columnName = 'timeout_hold_message_' . $i; $def->properties['timeout_hold_message_' . $i]->propertyName = 'timeout_hold_message_' . $i; $def->properties['timeout_hold_message_' . $i]->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; -} - -// How many times repeat timeout message -// 0 - infinity times -// 1 - one time -$def->properties['repeat_number'] = new ezcPersistentObjectProperty(); -$def->properties['repeat_number']->columnName = 'repeat_number'; -$def->properties['repeat_number']->propertyName = 'repeat_number'; -$def->properties['repeat_number']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['wait_timeout_reply_1'] = new ezcPersistentObjectProperty(); -$def->properties['wait_timeout_reply_1']->columnName = 'wait_timeout_reply_1'; -$def->properties['wait_timeout_reply_1']->propertyName = 'wait_timeout_reply_1'; -$def->properties['wait_timeout_reply_1']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['timeout_reply_message_1'] = new ezcPersistentObjectProperty(); -$def->properties['timeout_reply_message_1']->columnName = 'timeout_reply_message_1'; -$def->properties['timeout_reply_message_1']->propertyName = 'timeout_reply_message_1'; -$def->properties['timeout_reply_message_1']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['wait_timeout_reply_2'] = new ezcPersistentObjectProperty(); -$def->properties['wait_timeout_reply_2']->columnName = 'wait_timeout_reply_2'; -$def->properties['wait_timeout_reply_2']->propertyName = 'wait_timeout_reply_2'; -$def->properties['wait_timeout_reply_2']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['timeout_reply_message_2'] = new ezcPersistentObjectProperty(); -$def->properties['timeout_reply_message_2']->columnName = 'timeout_reply_message_2'; -$def->properties['timeout_reply_message_2']->propertyName = 'timeout_reply_message_2'; -$def->properties['timeout_reply_message_2']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['wait_timeout_reply_3'] = new ezcPersistentObjectProperty(); -$def->properties['wait_timeout_reply_3']->columnName = 'wait_timeout_reply_3'; -$def->properties['wait_timeout_reply_3']->propertyName = 'wait_timeout_reply_3'; -$def->properties['wait_timeout_reply_3']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; -$def->properties['timeout_reply_message_3'] = new ezcPersistentObjectProperty(); -$def->properties['timeout_reply_message_3']->columnName = 'timeout_reply_message_3'; -$def->properties['timeout_reply_message_3']->propertyName = 'timeout_reply_message_3'; -$def->properties['timeout_reply_message_3']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; + $def->properties['timeout_reply_message_' . $i] = new ezcPersistentObjectProperty(); + $def->properties['timeout_reply_message_' . $i]->columnName = 'timeout_reply_message_' . $i; + $def->properties['timeout_reply_message_' . $i]->propertyName = 'timeout_reply_message_' . $i; + $def->properties['timeout_reply_message_' . $i]->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; -$def->properties['wait_timeout_reply_4'] = new ezcPersistentObjectProperty(); -$def->properties['wait_timeout_reply_4']->columnName = 'wait_timeout_reply_4'; -$def->properties['wait_timeout_reply_4']->propertyName = 'wait_timeout_reply_4'; -$def->properties['wait_timeout_reply_4']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['timeout_reply_message_4'] = new ezcPersistentObjectProperty(); -$def->properties['timeout_reply_message_4']->columnName = 'timeout_reply_message_4'; -$def->properties['timeout_reply_message_4']->propertyName = 'timeout_reply_message_4'; -$def->properties['timeout_reply_message_4']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['wait_timeout_reply_5'] = new ezcPersistentObjectProperty(); -$def->properties['wait_timeout_reply_5']->columnName = 'wait_timeout_reply_5'; -$def->properties['wait_timeout_reply_5']->propertyName = 'wait_timeout_reply_5'; -$def->properties['wait_timeout_reply_5']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['timeout_reply_message_5'] = new ezcPersistentObjectProperty(); -$def->properties['timeout_reply_message_5']->columnName = 'timeout_reply_message_5'; -$def->properties['timeout_reply_message_5']->propertyName = 'timeout_reply_message_5'; -$def->properties['timeout_reply_message_5']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['bot_configuration'] = new ezcPersistentObjectProperty(); -$def->properties['bot_configuration']->columnName = 'bot_configuration'; -$def->properties['bot_configuration']->propertyName = 'bot_configuration'; -$def->properties['bot_configuration']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -// Ignore pending and assigned chat. -// Pending messages won't be send if chat is assigned -$def->properties['ignore_pa_chat'] = new ezcPersistentObjectProperty(); -$def->properties['ignore_pa_chat']->columnName = 'ignore_pa_chat'; -$def->properties['ignore_pa_chat']->propertyName = 'ignore_pa_chat'; -$def->properties['ignore_pa_chat']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['survey_timeout'] = new ezcPersistentObjectProperty(); -$def->properties['survey_timeout']->columnName = 'survey_timeout'; -$def->properties['survey_timeout']->propertyName = 'survey_timeout'; -$def->properties['survey_timeout']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['survey_id'] = new ezcPersistentObjectProperty(); -$def->properties['survey_id']->columnName = 'survey_id'; -$def->properties['survey_id']->propertyName = 'survey_id'; -$def->properties['survey_id']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['user_id'] = new ezcPersistentObjectProperty(); -$def->properties['user_id']->columnName = 'user_id'; -$def->properties['user_id']->propertyName = 'user_id'; -$def->properties['user_id']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; + $def->properties['wait_timeout_reply_' . $i] = new ezcPersistentObjectProperty(); + $def->properties['wait_timeout_reply_' . $i]->columnName = 'wait_timeout_reply_' . $i; + $def->properties['wait_timeout_reply_' . $i]->propertyName = 'wait_timeout_reply_' . $i; + $def->properties['wait_timeout_reply_' . $i]->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; +} return $def;
lhc_web/pos/lhabstract/erlhabstractmodelchatalerticon.php+6 −9 modified@@ -9,15 +9,12 @@ $def->idProperty->propertyName = 'id'; $def->idProperty->generator = new ezcPersistentGeneratorDefinition( 'ezcPersistentNativeGenerator' ); -$def->properties['name'] = new ezcPersistentObjectProperty(); -$def->properties['name']->columnName = 'name'; -$def->properties['name']->propertyName = 'name'; -$def->properties['name']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['identifier'] = new ezcPersistentObjectProperty(); -$def->properties['identifier']->columnName = 'identifier'; -$def->properties['identifier']->propertyName = 'identifier'; -$def->properties['identifier']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; +foreach (['name','identifier'] as $posAttr) { + $def->properties[$posAttr] = new ezcPersistentObjectProperty(); + $def->properties[$posAttr]->columnName = $posAttr; + $def->properties[$posAttr]->propertyName = $posAttr; + $def->properties[$posAttr]->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; +} return $def;
lhc_web/pos/lhabstract/erlhabstractmodelchatcolumn.php+13 −44 modified@@ -9,50 +9,19 @@ $def->idProperty->propertyName = 'id'; $def->idProperty->generator = new ezcPersistentGeneratorDefinition( 'ezcPersistentNativeGenerator' ); -$def->properties['column_name'] = new ezcPersistentObjectProperty(); -$def->properties['column_name']->columnName = 'column_name'; -$def->properties['column_name']->propertyName = 'column_name'; -$def->properties['column_name']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['column_icon'] = new ezcPersistentObjectProperty(); -$def->properties['column_icon']->columnName = 'column_icon'; -$def->properties['column_icon']->propertyName = 'column_icon'; -$def->properties['column_icon']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['column_identifier'] = new ezcPersistentObjectProperty(); -$def->properties['column_identifier']->columnName = 'column_identifier'; -$def->properties['column_identifier']->propertyName = 'column_identifier'; -$def->properties['column_identifier']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['variable'] = new ezcPersistentObjectProperty(); -$def->properties['variable']->columnName = 'variable'; -$def->properties['variable']->propertyName = 'variable'; -$def->properties['variable']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['position'] = new ezcPersistentObjectProperty(); -$def->properties['position']->columnName = 'position'; -$def->properties['position']->propertyName = 'position'; -$def->properties['position']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['enabled'] = new ezcPersistentObjectProperty(); -$def->properties['enabled']->columnName = 'enabled'; -$def->properties['enabled']->propertyName = 'enabled'; -$def->properties['enabled']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['conditions'] = new ezcPersistentObjectProperty(); -$def->properties['conditions']->columnName = 'conditions'; -$def->properties['conditions']->propertyName = 'conditions'; -$def->properties['conditions']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['chat_enabled'] = new ezcPersistentObjectProperty(); -$def->properties['chat_enabled']->columnName = 'chat_enabled'; -$def->properties['chat_enabled']->propertyName = 'chat_enabled'; -$def->properties['chat_enabled']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['online_enabled'] = new ezcPersistentObjectProperty(); -$def->properties['online_enabled']->columnName = 'online_enabled'; -$def->properties['online_enabled']->propertyName = 'online_enabled'; -$def->properties['online_enabled']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; +foreach (['column_name','column_icon','column_identifier','variable','conditions','popup_content'] as $posAttr) { + $def->properties[$posAttr] = new ezcPersistentObjectProperty(); + $def->properties[$posAttr]->columnName = $posAttr; + $def->properties[$posAttr]->propertyName = $posAttr; + $def->properties[$posAttr]->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; +} + +foreach (['icon_mode','position','enabled','chat_enabled','online_enabled','has_popup'] as $posAttr) { + $def->properties[$posAttr] = new ezcPersistentObjectProperty(); + $def->properties[$posAttr]->columnName = $posAttr; + $def->properties[$posAttr]->propertyName = $posAttr; + $def->properties[$posAttr]->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; +} return $def;
lhc_web/pos/lhabstract/erlhabstractmodelchatpriority.php+13 −24 modified@@ -9,30 +9,19 @@ $def->idProperty->propertyName = 'id'; $def->idProperty->generator = new ezcPersistentGeneratorDefinition( 'ezcPersistentNativeGenerator' ); -$def->properties['dep_id'] = new ezcPersistentObjectProperty(); -$def->properties['dep_id']->columnName = 'dep_id'; -$def->properties['dep_id']->propertyName = 'dep_id'; -$def->properties['dep_id']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['value'] = new ezcPersistentObjectProperty(); -$def->properties['value']->columnName = 'value'; -$def->properties['value']->propertyName = 'value'; -$def->properties['value']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; - -$def->properties['priority'] = new ezcPersistentObjectProperty(); -$def->properties['priority']->columnName = 'priority'; -$def->properties['priority']->propertyName = 'priority'; -$def->properties['priority']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['sort_priority'] = new ezcPersistentObjectProperty(); -$def->properties['sort_priority']->columnName = 'sort_priority'; -$def->properties['sort_priority']->propertyName = 'sort_priority'; -$def->properties['sort_priority']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; - -$def->properties['dest_dep_id'] = new ezcPersistentObjectProperty(); -$def->properties['dest_dep_id']->columnName = 'dest_dep_id'; -$def->properties['dest_dep_id']->propertyName = 'dest_dep_id'; -$def->properties['dest_dep_id']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; +foreach (['value'] as $posAttr) { + $def->properties[$posAttr] = new ezcPersistentObjectProperty(); + $def->properties[$posAttr]->columnName = $posAttr; + $def->properties[$posAttr]->propertyName = $posAttr; + $def->properties[$posAttr]->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING; +} + +foreach (['dep_id','priority','sort_priority','dest_dep_id'] as $posAttr) { + $def->properties[$posAttr] = new ezcPersistentObjectProperty(); + $def->properties[$posAttr]->columnName = $posAttr; + $def->properties[$posAttr]->propertyName = $posAttr; + $def->properties[$posAttr]->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT; +} return $def;
Vulnerability mechanics
Generated 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-9hgc-wpc5-v8p9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-1530ghsaADVISORY
- github.com/livehelperchat/livehelperchat/commit/edef7a8387be718d0de2dfd1e722789afb0461bcghsax_refsource_MISCWEB
- huntr.dev/bounties/8fd8de01-7e83-4324-9cc8-a97acb9b70d6ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.