Add some option to Global Chat

1. Report send to chat
2. Mentions in chat
This commit is contained in:
novgorodschi catalin
2026-09-10 08:20:42 +03:00
parent a7bb7d8dbd
commit 1035f06fd9
8 changed files with 514 additions and 5 deletions
@@ -97,7 +97,8 @@ trait DatabaseGlobalChatQueries {
// Faza 2: c.type/c.poll_id/c.deleted/c.edited - vezi editGlobalChatMessage(),
// deleteGlobalChatMessage() si createGlobalChatPoll() mai jos
$q = "SELECT c.id, c.id_user, c.date, c.msg, c.type, c.poll_id, c.deleted, c.edited,
// Faza 3: c.report_id - vezi shareGlobalChatReport() mai jos
$q = "SELECT c.id, c.id_user, c.date, c.msg, c.type, c.poll_id, c.report_id, c.deleted, c.edited,
u.username, u.access, a.tag AS ally_tag, a.id AS ally_id
FROM " . TB_PREFIX . "chat_global c
LEFT JOIN " . TB_PREFIX . "users u ON u.id = c.id_user
@@ -475,4 +476,118 @@ trait DatabaseGlobalChatQueries {
"DELETE FROM " . TB_PREFIX . "chat_mutes WHERE id_user = $targetUid"
) ? true : false;
}
/**
* Faza 3 (09.09.2026): cautare useri dupa inceputul username-ului, pentru
* autocomplete la @mentiuni. Exclude id 1-3 (Nature/Natars/conturi de
* sistem - vezi addNotice() din DatabaseMessageQueries.php, care le trateaza
* deja ca speciale). Scapam manual '%'/'_' din query ca sa nu functioneze
* ca wildcard-uri LIKE neintentionate daca cineva tasteaza chiar aceste
* caractere dupa @.
*/
function searchGlobalChatUsers($prefix, $limit = 8) {
$prefix = trim((string) $prefix);
$limit = (int) $limit;
if ($prefix === '') {
return [];
}
$likeSafe = str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $prefix);
list($eprefix) = $this->escape_input($likeSafe);
return $this->mysqli_fetch_all($this->query(
"SELECT id, username FROM " . TB_PREFIX . "users
WHERE username LIKE '$eprefix%' AND id > 3
ORDER BY username ASC
LIMIT $limit"
));
}
/**
* Faza 3 (09.09.2026): distribuie un raport de lupta propriu in chat-ul
* general - de atac SAU de aparare (cand te ataca altcineva pe tine,
* raportul TAU are tot ntype in acelasi set - vezi
* AutomationBattleResolution::[cod care apeleaza addNotice], unde
* atacatorul si apararea primesc fiecare propriul rand in `ndata`, cu
* ntype-uri complementare din SETUL de mai jos - t=3/TZ_ATTACKS din
* Message::noticeType() include deja ambele roluri, nu doar atacul).
* Include si perechea 22/23 (scenariu de atac separat, gasit tot in
* AutomationBattleResolution.php - nu e in intervalul 1-7 dar e tot
* un raport de lupta atac+aparare).
*
* Exclude intentionat intariri (8,15,16,17) si comert (10-13): acelea
* dezvaluie logistica/loturi, nepotrivite pentru difuzare pe tot
* serverul (chat-ul general nu are granita de alianta, deci un raport
* distribuit aici e vizibil oricui, inclusiv unui inamic) - acelasi
* filtru ca share-ul de alianta din berichte.php.
*
* NU atingem tabela ndata (folosita de tot sistemul de mesaje) - in loc,
* adaugam id-ul raportului intr-o allowlist separata (chat_global_shared_reports),
* verificata suplimentar in berichte.php la afisarea unui raport individual.
*
* @return array ['ok'=>bool, 'reason'=>string|null]
*/
function shareGlobalChatReport($uid, $noticeId) {
$uid = (int) $uid;
$noticeId = (int) $noticeId;
if ($uid <= 0 || $noticeId <= 0) {
return ['ok' => false, 'reason' => 'invalid'];
}
$notice = $this->getNotice2($noticeId, null);
if (!$notice) {
return ['ok' => false, 'reason' => 'notfound'];
}
// tine sincron cu acelasi set din berichte.php ($tzShareableNtypes)
$shareableNtypes = [1, 2, 3, 4, 5, 6, 7, 22, 23];
if ((int) $notice['uid'] !== $uid || !in_array((int) $notice['ntype'], $shareableNtypes, true)) {
return ['ok' => false, 'reason' => 'forbidden'];
}
$mutedUntil = $this->getGlobalChatMuteStatus($uid);
if ($mutedUntil !== null) {
return ['ok' => false, 'reason' => 'muted', 'mutedUntil' => $mutedUntil];
}
$now = time();
list($eNoticeId, $euid) = $this->escape_input($noticeId, $uid);
// allowlist: acest raport devine vizibil oricui e logat (vezi berichte.php)
$this->query(
"INSERT INTO " . TB_PREFIX . "chat_global_shared_reports (notice_id, shared_by, created)
VALUES ($eNoticeId, $euid, $now)
ON DUPLICATE KEY UPDATE shared_by = $euid, created = $now"
);
// mesajul-ancora in chat - topicul raportului (deja text afisabil,
// acelasi camp folosit si in lista de rapoarte din berichte.php)
$topic = trim((string) ($notice['topic'] ?? ''));
$topic = function_exists('mb_substr') ? mb_substr($topic, 0, 250) : substr($topic, 0, 250);
list($eTopic) = $this->escape_input($topic);
$this->query(
"INSERT INTO " . TB_PREFIX . "chat_global (id_user, date, msg, type, report_id)
VALUES ($euid, $now, '$eTopic', 'report', $eNoticeId)"
);
return ['ok' => true];
}
/**
* Verifica daca un raport a fost distribuit in chat-ul general - folosita
* de berichte.php ca o conditie suplimentara de acces (vezi acolo).
*/
function isGlobalChatSharedReport($noticeId) {
$noticeId = (int) $noticeId;
$row = mysqli_fetch_assoc($this->query(
"SELECT notice_id FROM " . TB_PREFIX . "chat_global_shared_reports WHERE notice_id = $noticeId"
));
return $row ? true : false;
}
}
+4
View File
@@ -4439,3 +4439,7 @@ tz_def('GCHAT_POLL_CREATE', 'Create poll');
tz_def('GCHAT_POLL_VOTES_WORD', 'votes');
tz_def('GCHAT_EMOJI_TITLE', 'Emoji');
tz_def('GCHAT_ERROR_GENERIC', 'Something went wrong.');
// Phase 3 (09.09.2026): @username mentions, share battle reports
tz_def('GCHAT_SHARE_REPORT', 'Share to chat');
tz_def('GCHAT_SHARE_REPORT_OK', 'Shared to chat!');
tz_def('GCHAT_REPORT_FALLBACK', 'Battle report');
+4
View File
@@ -4176,3 +4176,7 @@ tz_def('GCHAT_POLL_CREATE', 'Creeaza sondaj');
tz_def('GCHAT_POLL_VOTES_WORD', 'voturi');
tz_def('GCHAT_EMOJI_TITLE', 'Emoji');
tz_def('GCHAT_ERROR_GENERIC', 'A aparut o eroare.');
// Faza 3 (09.09.2026): mentiuni @username, distribuire rapoarte de lupta
tz_def('GCHAT_SHARE_REPORT', 'Distribuie in chat');
tz_def('GCHAT_SHARE_REPORT_OK', 'Distribuit in chat!');
tz_def('GCHAT_REPORT_FALLBACK', 'Raport de lupta');
@@ -0,0 +1,59 @@
<?php
#################################################################################
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
## --------------------------------------------------------------------------- ##
## Project: TravianZ ##
## Filename: Templates/GlobalChat/share_report_button.tpl ##
## Purpose: Buton "Distribuie in chat" pe pagina unui raport propriu de ##
## atac (berichte.php) - Faza 3 Global Chat. ##
## ##
## Inclus DOAR de berichte.php, DOAR cand $tzShareEligible e true (proprietar ##
## + ntype 1-7) - vezi acolo. id-ul raportului vine ca $_GET['id'], deja ##
## curatat in berichte.php inainte de a ajunge aici. ##
## ##
## Cerut de Catalin, 09.09.2026 (Faza 3 Global Chat). ##
## ##
## License: TravianZ Project ##
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
#################################################################################
$tzShareNoticeId = (int) preg_replace("/[^0-9]/", "", (string) ($_GET['id'] ?? 0));
?>
<div id="gchat_share_report_wrap" style="margin:8px 0;">
<button type="button" id="gchat_share_report_btn" data-id="<?php echo $tzShareNoticeId; ?>"
style="padding:4px 10px;border:1px solid #6b8f47;border-radius:4px;background:#6b8f47;color:#fff;cursor:pointer;font-size:12px;">
<?php echo GCHAT_SHARE_REPORT; ?>
</button>
<span id="gchat_share_report_status" style="margin-left:6px;font-size:12px;color:#666;"></span>
</div>
<script>
(function () {
"use strict";
var btn = document.getElementById('gchat_share_report_btn');
var status = document.getElementById('gchat_share_report_status');
if (!btn) { return; }
var OK_TXT = <?php echo json_encode(GCHAT_SHARE_REPORT_OK); ?>;
var ERR_TXT = <?php echo json_encode(GCHAT_ERROR_GENERIC); ?>;
btn.addEventListener('click', function () {
btn.disabled = true;
status.textContent = '';
fetch('ajax.php?f=gchat_share_report', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'id=' + encodeURIComponent(btn.getAttribute('data-id'))
}).then(function (r) { return r.json(); })
.then(function (data) {
btn.disabled = false;
status.textContent = (data && data.ok) ? OK_TXT : ERR_TXT;
})
.catch(function () {
btn.disabled = false;
status.textContent = ERR_TXT;
});
});
})();
</script>
+245 -4
View File
@@ -24,7 +24,7 @@
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
#################################################################################
?>
<div id="gchat_root" data-uid="<?php echo (int) $session->uid; ?>">
<div id="gchat_root" data-uid="<?php echo (int) $session->uid; ?>" data-username="<?php echo htmlspecialchars($session->username, ENT_QUOTES, 'UTF-8'); ?>">
<button id="gchat_bubble" type="button" title="<?php echo GCHAT_TITLE; ?>">
💬<span id="gchat_badge" style="display:none">0</span>
</button>
@@ -50,6 +50,8 @@
</div>
</div>
<div id="gchat_mention_list" style="display:none"></div>
<form id="gchat_form" autocomplete="off">
<button id="gchat_emoji_btn" type="button" class="gchat_toolbar_btn" title="<?php echo GCHAT_EMOJI_TITLE; ?>">🙂</button>
<button id="gchat_poll_btn" type="button" class="gchat_toolbar_btn" title="<?php echo GCHAT_POLL_TITLE; ?>">📊</button>
@@ -335,6 +337,50 @@
#gchat_poll_add_option { background: #ddd; }
#gchat_poll_submit { background: #6b8f47; color: #fff; }
/* Faza 3: mentiuni @username */
#gchat_mention_list {
display: none;
position: absolute;
left: 8px;
right: 8px;
bottom: 40px;
background: #fff;
border: 1px solid #ccc;
border-radius: 4px;
max-height: 120px;
overflow-y: auto;
box-shadow: 0 -2px 8px rgba(0,0,0,.15);
z-index: 10;
}
.gchat_mention_item {
padding: 4px 8px;
cursor: pointer;
font-size: 12px;
}
.gchat_mention_item:hover, .gchat_mention_item.active { background: #eef2e8; }
.gchat_mention { color: #1a5aa8; font-weight: bold; }
.gchat_msg_mentioned {
background: #fff6d5;
border-radius: 3px;
padding: 2px 3px;
margin: -2px -3px 4px -3px;
}
/* Faza 3: rapoarte de lupta distribuite in chat */
.gchat_report_block { margin-top: 2px; }
.gchat_report_link {
display: inline-block;
padding: 3px 6px;
background: #f2f0e6;
border: 1px solid #ddd6bd;
border-radius: 4px;
color: #6b4a1f;
text-decoration: none;
font-size: 11px;
}
.gchat_report_link:hover { text-decoration: underline; }
@media (max-width: 480px) {
#gchat_panel { right: 8px; bottom: 66px; }
#gchat_bubble { right: 8px; bottom: 8px; }
@@ -367,7 +413,8 @@
deletedPlaceholder: <?php echo json_encode(GCHAT_DELETED_PLACEHOLDER); ?>,
pollOptionPlaceholder: <?php echo json_encode(GCHAT_POLL_OPTION_PLACEHOLDER); ?>,
pollVotesWord: <?php echo json_encode(GCHAT_POLL_VOTES_WORD); ?>,
errorGeneric: <?php echo json_encode(GCHAT_ERROR_GENERIC); ?>
errorGeneric: <?php echo json_encode(GCHAT_ERROR_GENERIC); ?>,
reportFallback: <?php echo json_encode(GCHAT_REPORT_FALLBACK); ?>
};
var ACCESS_ADMIN = 9, ACCESS_MH = 8;
@@ -390,8 +437,10 @@
var pollForm = document.getElementById('gchat_poll_form');
var pollQuestionInput = document.getElementById('gchat_poll_question');
var pollOptionsBox = document.getElementById('gchat_poll_options');
var mentionList = document.getElementById('gchat_mention_list');
var myUid = parseInt(root.getAttribute('data-uid'), 10) || 0;
var myUsername = root.getAttribute('data-username') || '';
var lastId = 0;
var unread = 0;
var isOpen = false;
@@ -407,6 +456,12 @@
var MAX_POLL_OPTIONS = 6;
var EMOJI_LIST = ['😀','😂','😅','😊','😍','😎','🤔','😴','😭','😡','👍','👎','👏','🙏','💪','🔥','⭐','❤️','💯','🎉','⚔️','🛡️','🏰','🌾','🪵','⛏️','🧱','⏳','🐎','🏆'];
// Faza 3: stare pentru autocomplete la @mentiuni
var mentionMatches = [];
var mentionActiveIndex = -1;
var mentionTokenStart = -1;
var mentionTimer = null;
function fmtTime(unixTs) {
var d = new Date(unixTs * 1000);
function pad(n) { return (n < 10 ? '0' : '') + n; }
@@ -587,6 +642,44 @@
return wrap;
}
/**
* Faza 3: evidentiaza "@cuvant" in text (stil, nu neaparat un user real -
* verificare simpla, client-side, fara sa validam impotriva bazei de date
* la fiecare randare). Daca vreunul dintre ele e chiar username-ul
* vizualizatorului, intoarce true - renderMessage() adauga atunci un fundal
* pe tot randul, ca "notificare" vizuala (nu exista notificari separate,
* gen sunet/browser - in linie cu restul widget-ului, minimalist).
*/
function renderTextWithMentions(container, text) {
var re = /@([A-Za-z0-9_.\-]{2,32})/g;
var lastIndex = 0;
var match;
var mentionsMe = false;
while ((match = re.exec(text)) !== null) {
if (match.index > lastIndex) {
container.appendChild(document.createTextNode(text.slice(lastIndex, match.index)));
}
var mSpan = document.createElement('span');
mSpan.className = 'gchat_mention';
mSpan.textContent = '@' + match[1];
container.appendChild(mSpan);
if (myUsername && match[1].toLowerCase() === myUsername.toLowerCase()) {
mentionsMe = true;
}
lastIndex = re.lastIndex;
}
if (lastIndex < text.length) {
container.appendChild(document.createTextNode(text.slice(lastIndex)));
}
return mentionsMe;
}
function renderMessage(row) {
var line = document.createElement('div');
line.className = 'gchat_msg';
@@ -646,9 +739,34 @@
return line;
}
// Faza 3: raport de lupta distribuit - link catre berichte.php, cu
// topicul raportului (deja in row.msg) ca text vizibil
if (row.type === 'report') {
var reportBlock = document.createElement('div');
reportBlock.className = 'gchat_report_block';
var reportLink = document.createElement('a');
reportLink.href = 'berichte.php?id=' + encodeURIComponent(row.report_id);
reportLink.target = '_blank';
reportLink.rel = 'noopener';
reportLink.className = 'gchat_report_link';
reportLink.textContent = '\u2694\ufe0f ' + (row.msg || GCHAT_TXT.reportFallback);
reportBlock.appendChild(reportLink);
line.appendChild(reportBlock);
var reportActions = document.createElement('span');
reportActions.className = 'gchat_actions';
appendModActionLinks(reportActions, row);
if (reportActions.childNodes.length) { line.appendChild(reportActions); }
return line;
}
var text = document.createElement('span');
text.className = 'gchat_text';
text.textContent = row.msg;
if (renderTextWithMentions(text, row.msg)) {
line.classList.add('gchat_msg_mentioned');
}
line.appendChild(text);
var editedTag = document.createElement('span');
@@ -712,7 +830,11 @@
var textEl2 = line.querySelector('.gchat_text');
var editedTagEl2 = line.querySelector('.gchat_edited_tag');
if (textEl2) { textEl2.textContent = row.msg; }
if (textEl2) {
textEl2.textContent = '';
var mentionsMe2 = renderTextWithMentions(textEl2, row.msg);
line.classList.toggle('gchat_msg_mentioned', mentionsMe2);
}
if (editedTagEl2 && parseInt(row.edited, 10) === 1) {
editedTagEl2.style.display = 'inline';
}
@@ -878,6 +1000,125 @@
if (field.setSelectionRange) { field.setSelectionRange(pos, pos); }
}
// Faza 3: autocomplete la @mentiuni
function currentMentionToken() {
var pos = input.selectionStart;
var value = input.value;
if (pos == null) { return null; }
var atPos = value.lastIndexOf('@', pos - 1);
if (atPos === -1) { return null; }
// "@" trebuie sa fie inceput de cuvant (spatiu inainte, sau chiar
// inceputul mesajului) - altfel un email sau "cuvant@altceva" ar
// declansa gresit autocomplete-ul
if (atPos > 0 && !/\s/.test(value.charAt(atPos - 1))) { return null; }
var token = value.slice(atPos + 1, pos);
if (/[\s@]/.test(token)) { return null; }
return { start: atPos, query: token };
}
function closeMentionList() {
mentionList.style.display = 'none';
mentionList.innerHTML = '';
mentionMatches = [];
mentionActiveIndex = -1;
mentionTokenStart = -1;
}
function renderMentionList() {
mentionList.innerHTML = '';
mentionMatches.forEach(function (u, idx) {
var item = document.createElement('div');
item.className = 'gchat_mention_item' + (idx === mentionActiveIndex ? ' active' : '');
item.textContent = u.username;
// mousedown (nu click) - trebuie sa apuce inaintea lui 'blur' de pe input
item.addEventListener('mousedown', function (e) {
e.preventDefault();
selectMention(u.username);
});
mentionList.appendChild(item);
});
mentionList.style.display = mentionMatches.length ? 'block' : 'none';
}
function selectMention(username) {
if (mentionTokenStart === -1) { return; }
var pos = input.selectionStart;
var value = input.value;
var before = value.slice(0, mentionTokenStart);
var after = value.slice(pos);
var inserted = '@' + username + ' ';
input.value = before + inserted + after;
var newPos = (before + inserted).length;
input.focus();
if (input.setSelectionRange) { input.setSelectionRange(newPos, newPos); }
closeMentionList();
}
input.addEventListener('input', function () {
var token = currentMentionToken();
if (!token || token.query.length < 1) {
closeMentionList();
return;
}
mentionTokenStart = token.start;
if (mentionTimer) { window.clearTimeout(mentionTimer); }
mentionTimer = window.setTimeout(function () {
fetch(AJAX_URL + '?f=gchat_search_users&q=' + encodeURIComponent(token.query), { credentials: 'same-origin' })
.then(function (r) { return r.json(); })
.then(function (data) {
if (!data || !data.ok) { return; }
// token-ul s-ar fi putut schimba intre timp (cerere async) -
// verificam ca inca suntem pe acelasi "@cuvant" inainte sa
// afisam rezultate posibil deja irelevante
var stillSame = currentMentionToken();
if (!stillSame || stillSame.start !== mentionTokenStart) { return; }
mentionMatches = data.users || [];
mentionActiveIndex = mentionMatches.length ? 0 : -1;
renderMentionList();
})
.catch(function () { closeMentionList(); });
}, 150);
});
input.addEventListener('keydown', function (e) {
if (!mentionMatches.length) { return; }
if (e.key === 'ArrowDown') {
e.preventDefault();
mentionActiveIndex = (mentionActiveIndex + 1) % mentionMatches.length;
renderMentionList();
} else if (e.key === 'ArrowUp') {
e.preventDefault();
mentionActiveIndex = (mentionActiveIndex - 1 + mentionMatches.length) % mentionMatches.length;
renderMentionList();
} else if (e.key === 'Enter' || e.key === 'Tab') {
if (mentionActiveIndex >= 0) {
e.preventDefault();
selectMention(mentionMatches[mentionActiveIndex].username);
}
} else if (e.key === 'Escape') {
closeMentionList();
}
});
input.addEventListener('blur', function () {
// delay ca sa apuce mousedown-ul pe un item din lista inainte sa o inchidem
window.setTimeout(closeMentionList, 150);
});
function addPollOptionRow(value) {
if (pollOptionsBox.children.length >= MAX_POLL_OPTIONS) { return; }
+34
View File
@@ -248,6 +248,40 @@ switch(isset($_GET['f']) ? $_GET['f'] : '') {
echo json_encode($database->voteGlobalChatPoll($uid, $_POST['pollId'] ?? 0, $_POST['option'] ?? -1));
break;
// Faza 3 (09.09.2026): autocomplete la @mentiuni - cautare useri dupa
// inceputul username-ului. GET, nu necesita alta permisiune decat login.
case 'gchat_search_users':
header('Content-Type: application/json');
if (!isset($_SESSION)) {
session_start();
}
include_once($autoprefix.'GameEngine/Database.php');
$uid = (int) ($_SESSION['id_user'] ?? 0);
if (!$uid) {
http_response_code(403);
echo json_encode(['ok' => 0, 'reason' => 'notloggedin']);
break;
}
echo json_encode(['ok' => 1, 'users' => $database->searchGlobalChatUsers($_GET['q'] ?? '')]);
break;
// Faza 3 (09.09.2026): distribuie un raport de lupta propriu in chat.
// Verificarea de tip+proprietate se face in Database::shareGlobalChatReport().
case 'gchat_share_report':
header('Content-Type: application/json');
if (!isset($_SESSION)) {
session_start();
}
include_once($autoprefix.'GameEngine/Database.php');
$uid = (int) ($_SESSION['id_user'] ?? 0);
if (!$uid) {
http_response_code(403);
echo json_encode(['ok' => 0, 'reason' => 'notloggedin']);
break;
}
echo json_encode($database->shareGlobalChatReport($uid, $_POST['id'] ?? 0));
break;
case 'gchat_mute':
case 'gchat_block':
case 'gchat_unmute':
+33
View File
@@ -157,6 +157,8 @@ if (isset($_GET['t']) && (int) $_GET['t'] === 3) {
<?php
if (isset($_GET['id']))
{
$tzShareEligible = false;
if (isset($_GET['aid']) && $_GET['aid'] > 0 && $_GET['aid'] == $session->alliance && $database->getNotice2($_GET['id'], 'ally') == $session->alliance)
{
$type = $database->getNotice2($_GET['id'], 'ntype');
@@ -170,9 +172,40 @@ if (isset($_GET['id']))
elseif($database->getNotice2(preg_replace("/[^a-zA-Z0-9_-]/", "", $_GET['id']), 'uid') == $session->uid)
{
$type = ($message->readingNotice['ntype'] == 9) ? $message->readingNotice['archive'] : $message->readingNotice['ntype'];
// Faza 3 Global Chat (09.09.2026): doar proprietarul vazand propriul
// raport poate primi butonul de distribuire, si doar rapoarte de
// LUPTA - atac SAU aparare (cand te ataca altcineva pe tine, raportul
// TAU are tot un ntype din acelasi set - t=3/TZ_ATTACKS din
// Message::noticeType() include deja ambele roluri). Verificam ntype-ul
// ORIGINAL, nefiltrat (nu $type, care mai sus poate fi deja remapat pe
// arhiva). Tine sincron cu $shareableNtypes din
// Database::shareGlobalChatReport().
$tzShareableNtypes = [1, 2, 3, 4, 5, 6, 7, 22, 23];
$tzOwnNtype = $message->readingNotice['ntype'] ?? null;
if ($tzOwnNtype !== null && in_array((int) $tzOwnNtype, $tzShareableNtypes, true)) {
$tzShareEligible = true;
}
}
elseif ($database->isGlobalChatSharedReport($_GET['id']))
{
// Faza 3 Global Chat (09.09.2026): raport distribuit explicit in
// chat-ul general de catre proprietarul lui - vizibil oricui e logat,
// indiferent de alianta. Acelasi filtru de siguranta ca la share-ul
// de alianta mai sus (10-17 raman ascunse), desi in practica
// Database::shareGlobalChatReport() deja refuza sa distribuie orice
// in afara de ntype 1-7 - dublam verificarea aici din prudenta.
$type = $database->getNotice2($_GET['id'], 'ntype');
if ($type >= 10 && $type <= 17) unset($type);
}
if(isset($type)) include("Templates/Notice/".$message->getReportType($type).".tpl");
// Faza 3 Global Chat: butonul "Distribuie in chat", doar cand eligibil (vezi mai sus)
if ($tzShareEligible) {
include("Templates/GlobalChat/share_report_button.tpl");
}
unset($type);
}
else include("Templates/Notice/all.tpl");
+19
View File
@@ -595,6 +595,7 @@ CREATE TABLE IF NOT EXISTS `%PREFIX%chat_global` (
`msg` varchar(250) NOT NULL,
`type` varchar(10) NOT NULL DEFAULT 'text',
`poll_id` int(20) NULL DEFAULT NULL,
`report_id` int(20) NULL DEFAULT NULL,
`deleted` tinyint(1) NOT NULL DEFAULT 0,
`edited` tinyint(1) NOT NULL DEFAULT 0,
`updated_at` int(11) NULL DEFAULT NULL,
@@ -658,6 +659,24 @@ CREATE TABLE IF NOT EXISTS `%PREFIX%chat_global_poll_votes` (
KEY `poll_id` (`poll_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- --------------------------------------------------------
--
-- Faza 3 (09.09.2026): allowlist de rapoarte distribuite in chat-ul general.
-- NU atingem tabela `ndata` (folosita de tot sistemul de mesaje/rapoarte) -
-- in loc, un raport prezent aici e vizibil oricui e logat, indiferent de
-- alianta (vezi berichte.php, verificarea de acces). notice_id e PRIMARY
-- KEY: un raport se distribuie o singura data in allowlist (re-distribuirea
-- doar posteaza un mesaj nou in chat, vezi Database::shareGlobalChatReport).
--
CREATE TABLE IF NOT EXISTS `%PREFIX%chat_global_shared_reports` (
`notice_id` int(11) NOT NULL,
`shared_by` int(11) NOT NULL,
`created` int(11) NOT NULL,
PRIMARY KEY (`notice_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------