Skip to content

Commit cc2a31f

Browse files
committed
feat: 🌍 Enhance message content protection with multilingual support
- Added language-specific warning message support for ghosting/masking rules in the message content protection feature. πŸ›‘οΈ - Redesigned the UI for the message protection warning editor, incorporating multilingual tabs and per-language message fields for better user experience. 🎨 - Implemented runtime masking that allows warning text to be translated based on chat locale, with full locale and short locale fallback. 🌐 - Updated the data/model layer to include `languages` persistence support in the `lh_abstract_msg_protection` model/POS mapping. πŸ“Š - Simplified the rendering of multilingual tab content in the Svelte component used by admin forms, improving code maintainability. 🧹 - Updated database structure to include a new `languages` field in the `lh_abstract_msg_protection` table. πŸ—„οΈ - Incremented version numbers to reflect the changes: DB_VERSION to 347 and LHC_RELEASE to 480. πŸ”’ This release extends the message protection rules with localized warning messages, ensuring a more tailored experience for users across different languages. πŸš€
1 parent ae542e0 commit cc2a31f

10 files changed

Lines changed: 153 additions & 35 deletions

File tree

β€Žlhc_web/design/defaulttheme/js/svelte/public/build/languages.jsβ€Ž

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žlhc_web/design/defaulttheme/js/svelte/public/build/languages.js.mapβ€Ž

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žlhc_web/design/defaulttheme/js/svelte/src/Widgets/LHCMultilanguageTabContent.svelteβ€Ž

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -187,29 +187,21 @@
187187
<DepartamentSelection on:department_select={(dep_id) => {selectDepartment(dep_id, lang)}} on:department_unselect={(dep_id) => {unselectDepartment(dep_id, lang)}} index_block={index} selected_departments={lang.dep_ids}></DepartamentSelection>
188188
{/if}
189189

190-
191190
{#if fields.length > 0}
192-
<ul class="nav nav-pills" role="tablist">
193-
<li role="presentation" class="nav-item"><a class="nav-link active" href="#main-extension-lang-{index}" aria-controls="main-extension-lang-{index}" role="tab" data-bs-toggle="tab" >{$t('user_account.messages')}</a></li>
194-
</ul>
195-
<div class="tab-content">
196-
<div role="tabpanel" class="tab-pane active" id="main-extension-lang-{index}">
197-
<div class="row">
198-
{#each fields as field}
199-
<div class={"col-"+(field.column ? field.column : '12')}>
200-
{#if field.type === 'header_block'}
201-
<h4>{field.name}</h4>
202-
{:else}
203-
<div class="form-group">
204-
{#if field.name_literal}<label>{field.name_literal}</label>{/if}
205-
<BBCodeToolbar selector="#{field.name}-{index}"></BBCodeToolbar>
206-
<textarea class="form-control" rows="2" id={field.name+"-"+index} name={field.name+"["+index+"]"} bind:value={lang[field['bind_name']]}></textarea>
207-
</div>
208-
{/if}
209-
</div>
210-
{/each}
191+
<div class="row">
192+
{#each fields as field}
193+
<div class={"col-"+(field.column ? field.column : '12')}>
194+
{#if field.type === 'header_block'}
195+
<h4>{field.name}</h4>
196+
{:else}
197+
<div class="form-group">
198+
{#if field.name_literal}<label>{field.name_literal}</label>{/if}
199+
<BBCodeToolbar selector="#{field.name}-{index}"></BBCodeToolbar>
200+
<textarea class="form-control" rows="2" id={field.name+"-"+index} name={field.name+"["+index+"]"} bind:value={lang[field['bind_name']]}></textarea>
201+
</div>
202+
{/if}
211203
</div>
212-
</div>
204+
{/each}
213205
</div>
214206
{/if}
215207

β€Žlhc_web/design/defaulttheme/tpl/lhabstract/custom/message_content_protection.tpl.phpβ€Ž

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,42 @@
6767
</h2>
6868
<div id="collapseWarning" class="accordion-collapse collapse" aria-labelledby="headingWarning" data-bs-parent="#accordionMsgProtection">
6969
<div class="accordion-body">
70-
<div class="form-group">
71-
<div class="pb-1">
72-
<label class="pe-1"><?php echo $fields['v_warning']['trans'];?></label><button class="btn btn-xs btn-secondary me-1" id="sample-button" type="button"><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('abstract/message_protection','Sample');?></button>
70+
71+
<ul class="nav nav-tabs mb-2" role="tablist" id="languageProtection-tabs">
72+
<a class="nav-link active" href="#main" aria-controls="main" role="tab" data-bs-toggle="tab" aria-selected="true"><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('abstract/message_protection','Main');?></a>
73+
<lhc-multilanguage-tab identifier="languageProtection" <?php if ($object->languages != '') : ?>init_langauges="<?php echo ($object->id > 0 ? $object->id : 0)?>"<?php endif;?>></lhc-multilanguage-tab>
74+
</ul>
75+
76+
<script>
77+
78+
<?php if ($object->languages != '') : ?>
79+
var languageProtection<?php echo $object->id?> = <?php echo json_encode(json_decode($object->languages, true), JSON_HEX_APOS) ?>;
80+
<?php endif; ?>
81+
82+
var languageDialects = <?php echo json_encode(array_values(erLhcoreClassModelSpeechLanguageDialect::getDialectsGrouped()))?>;
83+
84+
window.languageProtectionFields = <?php echo json_encode([
85+
[
86+
'name' => 'message_lang',
87+
'bind_name' => 'message',
88+
'name_literal' => erTranslationClassLhTranslation::getInstance()->getTranslation('chat/cannedmsg','Message')
89+
]
90+
])?>;
91+
</script>
92+
93+
<div class="tab-content">
94+
<div role="tabpanel" class="tab-pane active" id="main">
95+
<div class="form-group">
96+
<div class="pb-1">
97+
<label class="pe-1"><?php echo $fields['v_warning']['trans'];?></label><button class="btn btn-xs btn-secondary me-1" id="sample-button" type="button"><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('abstract/message_protection','Sample');?></button>
98+
</div>
99+
<?php echo erLhcoreClassAbstract::renderInput('v_warning', $fields['v_warning'], $object)?>
100+
</div>
73101
</div>
74-
<?php echo erLhcoreClassAbstract::renderInput('v_warning', $fields['v_warning'], $object)?>
102+
<lhc-multilanguage-tab-content identifier="languageProtection" <?php if ($object->languages != '') : ?>init_langauges="<?php echo ($object->id > 0 ? $object->id : 0)?>"<?php endif;?>></lhc-multilanguage-tab-content>
75103
</div>
104+
105+
76106
</div>
77107
</div>
78108
</div>

β€Žlhc_web/doc/CHANGELOG.txtβ€Ž

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
4.80v
2+
3+
1. Notable changes since 4.79v
4+
- Message content protection: added language-specific warning message support for ghosting/masking rules.
5+
- UI (back office): redesigned message protection warning editor with multilingual tabs and per-language message fields.
6+
- Runtime masking: warning text can now be translated by chat locale (full locale and short locale fallback).
7+
- Data/model layer: added `languages` persistence support in `lh_abstract_msg_protection` model/POS mapping.
8+
- Frontend cleanup: simplified multilingual tab content rendering in Svelte component used by admin forms.
9+
10+
2. Summary
11+
- This release extends message protection rules with localized warning messages and wires the full stack (DB, model, UI, and runtime locale resolution).
12+
13+
execute doc/update_db/update_347.sql for update
14+
115
4.79v
216

317
1. Notable changes since 4.78v

β€Žlhc_web/doc/update_db/structure.jsonβ€Ž

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,16 @@
184184
"default": null,
185185
"extra": "",
186186
"collation": "utf8mb4_unicode_ci"
187-
}
187+
},
188+
{
189+
"field": "languages",
190+
"type": "text",
191+
"null": "NO",
192+
"key": "",
193+
"default": null,
194+
"extra": "",
195+
"collation": "utf8mb4_unicode_ci"
196+
}
188197
],
189198
"lhc_mailconv_mailing_list_recipient": [
190199
{
@@ -12469,7 +12478,7 @@
1246912478
"lh_generic_bot_rest_api_cache" : "CREATE TABLE `lh_generic_bot_rest_api_cache` (\n `hash` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,\n `rest_api_id` bigint(20) unsigned NOT NULL,\n `response` text NOT NULL,\n `ctime` bigint(20) NOT NULL,\n UNIQUE KEY `rest_api_id_hash` (`rest_api_id`,`hash`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
1247012479
"lhc_mailconv_oauth_ms" : "CREATE TABLE `lhc_mailconv_oauth_ms` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\n `mailbox_id` bigint(20) unsigned NOT NULL,\n `oauth_uid` varchar(50) NOT NULL,\n `name` varchar(200) NOT NULL,\n `email` varchar(200) NOT NULL,\n `surname` varchar(200) NOT NULL,\n `display_name` varchar(200) NOT NULL,\n `txtSessionKey` varchar(255) NOT NULL,\n `txtCodeVerifier` varchar(255) NOT NULL,\n `dtExpires` bigint(20) unsigned NOT NULL,\n `txtRefreshToken` text NOT NULL,\n `txtToken` text NOT NULL,\n `txtIDToken` text NOT NULL,\n `completed` tinyint(1) unsigned NOT NULL,\n PRIMARY KEY (`id`),\n KEY `oauth_uid` (`oauth_uid`),\n KEY `user_id_completed` (`mailbox_id`,`completed`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4\n;",
1247112480
"lh_userdep_alias" : "CREATE TABLE `lh_userdep_alias` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,`dep_id` bigint(20) unsigned NOT NULL,`dep_group_id` bigint(20) unsigned NOT NULL, `job_title` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, `user_id` bigint(20) unsigned NOT NULL,`nick` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,`filepath` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,`filename` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,`avatar` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`id`), KEY `dep_id_user_id` (`dep_id`,`user_id`), KEY `dep_group_id_user_id` (`dep_group_id`,`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
12472-
"lh_abstract_msg_protection" : "CREATE TABLE `lh_abstract_msg_protection` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `pattern` text COLLATE utf8mb4_unicode_ci NOT NULL, `enabled` int(11) NOT NULL DEFAULT 1, `remove` int(11) NOT NULL DEFAULT 0, `v_warning` text COLLATE utf8mb4_unicode_ci NOT NULL, `rule_type` tinyint(1) unsigned NOT NULL DEFAULT 0, `has_dep` tinyint(1) unsigned NOT NULL DEFAULT 0, `name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, `dep_ids` text COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`id`), KEY `enabled_type` (`enabled`,`rule_type`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
12481+
"lh_abstract_msg_protection" : "CREATE TABLE `lh_abstract_msg_protection` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `pattern` text COLLATE utf8mb4_unicode_ci NOT NULL, `enabled` int(11) NOT NULL DEFAULT 1, `remove` int(11) NOT NULL DEFAULT 0, `languages` text COLLATE utf8mb4_unicode_ci NOT NULL, `v_warning` text COLLATE utf8mb4_unicode_ci NOT NULL, `rule_type` tinyint(1) unsigned NOT NULL DEFAULT 0, `has_dep` tinyint(1) unsigned NOT NULL DEFAULT 0, `name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, `dep_ids` text COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`id`), KEY `enabled_type` (`enabled`,`rule_type`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
1247312482
"lh_chat_participant" : "CREATE TABLE `lh_chat_participant` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\n `chat_id` bigint(20) NOT NULL,\n `user_id` bigint(20) NOT NULL,\n `duration` int(11) unsigned NOT NULL,\n `time` bigint(20) unsigned NOT NULL,\n `dep_id` bigint(20) unsigned NOT NULL,\n PRIMARY KEY (`id`),\n KEY `chat_id` (`chat_id`),\n KEY `time` (`time`),\n KEY `user_id` (`user_id`)\n) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
1247412483
"lh_brand" : "CREATE TABLE `lh_brand` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
1247512484
"lh_brand_member" : "CREATE TABLE `lh_brand_member` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `dep_id` bigint(20) unsigned NOT NULL, `brand_id` bigint(20) unsigned NOT NULL, `role` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,\n PRIMARY KEY (`id`),\n KEY `dep_id` (`dep_id`),\n KEY `brand_id_role` (`brand_id`,`role`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",

β€Žlhc_web/lib/core/lhcore/lhupdate.phpβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
class erLhcoreClassUpdate
44
{
5-
const DB_VERSION = 346;
6-
const LHC_RELEASE = 479;
5+
const DB_VERSION = 347;
6+
const LHC_RELEASE = 480;
77

88
public static function doTablesUpdate($definition){
99
$updateInformation = self::getTablesStatus($definition);

β€Žlhc_web/lib/vendor_lhc/LiveHelperChat/Models/LHCAbstract/ChatMessagesGhosting.phpβ€Ž

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ public function getState()
2929
'rule_type' => $this->rule_type,
3030
'has_dep' => $this->has_dep,
3131
'dep_ids' => $this->dep_ids,
32-
'name' => $this->name
32+
'name' => $this->name,
33+
'languages' => $this->languages
3334
);
3435

3536
return $stateArray;
@@ -83,6 +84,7 @@ public static function shouldMask($user_id) {
8384
public static function maskVisitorMessages(& $messages, \erLhcoreClassModelChat $chat, $type = self::MSG_TYPE_VISITOR_TO_OPERATOR) {
8485
$user_id = $chat->user_id;
8586
$dep_id = $chat->dep_id;
87+
$locale = isset($chat->chat_locale) ? $chat->chat_locale : '';
8688

8789
// Create a cache key based on type and department
8890
$cacheKey = $type . '_' . $dep_id;
@@ -109,6 +111,11 @@ public static function maskVisitorMessages(& $messages, \erLhcoreClassModelChat
109111
return $messages;
110112
}
111113

114+
if ($locale != '') {
115+
$maskRule = clone $maskRule;
116+
$maskRule->translateByChat($locale);
117+
}
118+
112119
// Only check permissions if user is assigned and we have a rule to apply
113120
if ($user_id > 0 && !self::shouldMask($user_id)) {
114121
return $messages;
@@ -358,7 +365,7 @@ public function getFields()
358365

359366
public function dependFooterJs()
360367
{
361-
return '<script type="module" src="'. \erLhcoreClassDesign::designJSStatic('js/svelte/public/build/departments.js').'"></script><script type="module" src="'. \erLhcoreClassDesign::designJSStatic('js/svelte/public/build/masking.js').'"></script>';
368+
return '<script type="module" src="'. \erLhcoreClassDesign::designJSStatic('js/svelte/public/build/departments.js').'"></script><script type="module" src="' . \erLhcoreClassDesign::designJSStatic('js/svelte/public/build/masking.js').'"></script><script type="module" src="' . \erLhcoreClassDesign::designJSStatic('js/svelte/public/build/languages.js').'"></script>';
362369
}
363370

364371
public function getModuleTranslations()
@@ -403,6 +410,70 @@ public function __get($var)
403410
}
404411
}
405412

413+
public function setTranslationData($data)
414+
{
415+
if (isset($data['message']) && $data['message'] != '') {
416+
$this->v_warning = $data['message'];
417+
}
418+
}
419+
420+
public function translateByChat($locale)
421+
{
422+
if ($locale == '' || $this->languages == '') {
423+
return;
424+
}
425+
426+
$languages = json_decode($this->languages, true);
427+
428+
if (!is_array($languages)) {
429+
return;
430+
}
431+
432+
foreach ($languages as $data) {
433+
if (isset($data['languages']) && is_array($data['languages']) && in_array($locale, $data['languages'])) {
434+
$this->setTranslationData($data);
435+
return;
436+
}
437+
}
438+
439+
$localeShort = explode('-', $locale)[0];
440+
foreach ($languages as $data) {
441+
if (isset($data['languages']) && is_array($data['languages']) && in_array($localeShort, $data['languages'])) {
442+
$this->setTranslationData($data);
443+
return;
444+
}
445+
}
446+
}
447+
448+
public function validateInput($params = array())
449+
{
450+
$definition = array(
451+
'languages' => new \ezcInputFormDefinitionElement(\ezcInputFormDefinitionElement::OPTIONAL, 'unsafe_raw', null, FILTER_REQUIRE_ARRAY),
452+
'message_lang' => new \ezcInputFormDefinitionElement(\ezcInputFormDefinitionElement::OPTIONAL, 'unsafe_raw', null, FILTER_REQUIRE_ARRAY),
453+
);
454+
455+
$form = new \ezcInputForm(INPUT_POST, $definition);
456+
457+
$languagesData = [];
458+
459+
if ($form->hasValidData('languages') && !empty($form->languages)) {
460+
foreach ($form->languages as $index => $languages) {
461+
$languagesData[] = [
462+
'message' => isset($form->message_lang[$index]) ? $form->message_lang[$index] : '',
463+
'languages' => $languages,
464+
];
465+
}
466+
}
467+
468+
$this->languages = json_encode($languagesData, JSON_HEX_APOS);
469+
$this->languages_array = $languagesData;
470+
}
471+
472+
public function beforeSave()
473+
{
474+
$this->has_dep = $this->dep_ids == '' || $this->dep_ids == '[]' ? 0 : 1;
475+
}
476+
406477
public function beforeUpdate()
407478
{
408479
$this->has_dep = $this->dep_ids == '' || $this->dep_ids == '[]' ? 0 : 1;
@@ -421,4 +492,5 @@ public function beforeUpdate()
421492
public $has_dep = 0;
422493
public $dep_ids = '';
423494
public $name = '';
495+
public $languages = '';
424496
}

β€Žlhc_web/modules/lhinstall/install.phpβ€Ž

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1580,7 +1580,7 @@
15801580
('preload_iframes','0','0','Preload widget. It will avoid loading delay after clicking widget','0'),
15811581
('product_show_departament','0','0','Enable products show by departments', '1'),
15821582
('paidchat_data','','0','Paid chat configuration','1'),
1583-
('version_updates', '346', 0, '', 1),
1583+
('version_updates', '347', 0, '', 1),
15841584
('del_on_close_no_msg','0','0','Delete chat on close if there are no messages from the visitor','0'),
15851585
('mheight_op','200','0','Messages box height for operator','0'),
15861586
('listd_op','10','0','Default number of online operators to show','0'),
@@ -2288,6 +2288,7 @@
22882288
`enabled` int(11) NOT NULL DEFAULT 1,
22892289
`remove` int(11) NOT NULL DEFAULT 0,
22902290
`v_warning` text COLLATE utf8mb4_unicode_ci NOT NULL,
2291+
`languages` text COLLATE utf8mb4_unicode_ci NOT NULL,
22912292
`rule_type` tinyint(1) unsigned NOT NULL DEFAULT 0,
22922293
`has_dep` tinyint(1) unsigned NOT NULL DEFAULT 0,
22932294
`name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,

β€Žlhc_web/pos/lhabstract/livehelperchat/models/lhcabstract/chatmessagesghosting.phpβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
$def->properties[$posAttr]->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT;
1717
}
1818

19-
foreach (['pattern','v_warning','name','dep_ids'] as $posAttr) {
19+
foreach (['pattern','v_warning','name','dep_ids','languages'] as $posAttr) {
2020
$def->properties[$posAttr] = new ezcPersistentObjectProperty();
2121
$def->properties[$posAttr]->columnName = $posAttr;
2222
$def->properties[$posAttr]->propertyName = $posAttr;

0 commit comments

Comments
Β (0)