properly implement forum notifications

This commit is contained in:
Mario
2025-10-12 15:29:50 +00:00
parent 3cdfa94c29
commit 83f6846143
5 changed files with 118 additions and 147 deletions

View File

@@ -135,7 +135,6 @@ class Network extends \Zotlabs\Web\Controller {
$status_editor = '';
if (Apps::system_app_installed(local_channel(), 'Affinity Tool')) {
$affinity_locked = intval(get_pconfig(local_channel(), 'affinity', 'lock', 1));
if ($affinity_locked) {
@@ -273,18 +272,6 @@ class Network extends \Zotlabs\Web\Controller {
// This is for nouveau view cid queries (not a public forum)
$sql_extra = " AND author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ";
}
elseif($pf && $unseen && $nouveau) {
$vnotify = get_pconfig(local_channel(), 'system', 'vnotify');
$likes_sql = '';
if (!($vnotify & VNOTIFY_LIKE)) {
$likes_sql = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
// This is for nouveau view public forum cid queries (if a forum notification is clicked)
$sql_extra = " AND item.parent IN (SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal) AND item_unseen = 1 AND verb != 'Announce' $likes_sql ";
}
else {
// This is for threaded view cid queries (e.g. if a forum is selected from the forum filter)
$sql_extra = " AND item.parent IN (SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal) ";

View File

@@ -91,8 +91,14 @@ class Sse_bs extends Controller {
default:
}
$selected_forum_id = null;
if (str_starts_with(argv(1), 'forum_')) {
$selected_forum_id = argv(1);
$f = 'bs_forums';
}
if(self::$offset && $f) {
$result = self::$f(true);
$result = self::$f($selected_forum_id ?? true);
json_return_and_die($result);
}
@@ -102,7 +108,7 @@ class Sse_bs extends Controller {
self::bs_home($home),
self::bs_notify(),
self::bs_intros(),
self::bs_forums(),
self::bs_forums($selected_forum_id),
self::bs_pubs($pubs),
self::bs_files(),
self::bs_all_events(),
@@ -610,69 +616,94 @@ class Sse_bs extends Controller {
}
function bs_forums() {
function bs_forums($selected_forum_id) {
$result['forums']['notifications'] = [];
$result['forums']['count'] = 0;
$result['forums']['offset'] = -1;
if(! self::$uid)
return $result;
if(! (self::$vnotify & VNOTIFY_FORUMS))
if(!self::$uid || !(self::$vnotify & VNOTIFY_FORUMS)) {
$result['forum']['notifications'] = [];
$result['forum']['count'] = 0;
$result['forum']['offset'] = -1;
return $result;
}
$forums = get_forum_channels(self::$uid);
if($forums) {
$item_normal = item_normal();
$p_sql = '';
$sql_extra = '';
if(! (self::$vnotify & VNOTIFY_LIKE))
$sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$fcount = count($forums);
$i = 0;
for($x = 0; $x < $fcount; $x ++) {
$r = q("select count(*) as total from item
where uid = %d and (owner_xchan = '%s' or author_xchan = '%s') and author_xchan != '%s' and verb != 'Announce' and item_unseen = 1 $sql_extra $item_normal",
$forum_id = 'forum_' . $forums[$x]['abook_id'];
$result[$forum_id]['notifications'] = [];
$result[$forum_id]['count'] = 0;
$limit = intval(self::$limit);
$offset = self::$offset;
$sql_extra = '';
if (!(self::$vnotify & VNOTIFY_LIKE)) {
$sql_extra = " AND item.verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
elseif (!feature_enabled(self::$uid, 'dislike')) {
$sql_extra = " AND item.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
$item_normal = item_normal();
// Filter internal follow activities and strerams add/remove activities
$item_normal .= " AND item.verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($forum_id === $selected_forum_id) {
$items = q("SELECT item.*, tp.uuid AS thr_parent_uuid FROM item
LEFT JOIN item tp ON item.thr_parent = tp.mid AND item.uid = tp.uid
WHERE item.uid = %d
AND item.created <= '%s'
AND item.owner_xchan = '%s'
AND item.item_unseen = 1 AND item.item_wall = 0 AND item.item_private IN (0, 1)
AND item.obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
AND NOT (item.verb = 'Announce' AND item.item_thread_top = 1) -- only show the announce activity and not the resulting item
AND NOT item.author_xchan = '%s'
$item_normal
$sql_extra
ORDER BY item.created DESC LIMIT $limit OFFSET $offset",
intval(self::$uid),
dbescdate($_SESSION['sse_loadtime']),
dbescdate($forums[$x]['xchan_hash']),
dbesc(self::$ob_hash)
);
if ($items) {
$result[$forum_id]['offset'] = ((count($items) == $limit) ? intval($offset + $limit) : -1);
xchan_query($items);
foreach($items as $item) {
$parsed = Enotify::format($item);
if($parsed) {
$result[$forum_id]['notifications'][] = $parsed;
}
}
}
else {
$result[$forum_id]['offset'] = -1;
}
}
$r = q("SELECT id FROM item
WHERE uid = %d and item_unseen = 1 AND item_wall = 0 AND item_private IN (0, 1)
AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image')
AND author_xchan != '%s'
AND item.owner_xchan = '%s'
$item_normal
$sql_extra LIMIT 100",
intval(self::$uid),
dbesc($forums[$x]['xchan_hash']),
dbesc($forums[$x]['xchan_hash']),
dbesc(self::$ob_hash)
dbesc(self::$ob_hash),
dbesc($forums[$x]['xchan_hash'])
);
if($r[0]['total']) {
$forums[$x]['notify_link'] = z_root() . '/network/?f=&pf=1&unseen=1&cid=' . $forums[$x]['abook_id'];
$forums[$x]['name'] = $forums[$x]['xchan_name'];
$forums[$x]['addr'] = $forums[$x]['xchan_addr'] ?? $forums[$x]['xchan_url'];
$forums[$x]['url'] = $forums[$x]['xchan_url'];
$forums[$x]['photo'] = $forums[$x]['xchan_photo_s'];
$forums[$x]['unseen'] = $r[0]['total'];
$forums[$x]['private_forum'] = ((isset($forums[$x]['private_forum']) && $forums[$x]['private_forum']) ? 'lock' : '');
$forums[$x]['message'] = ((isset($forums[$x]['private_forum']) && $forums[$x]['private_forum']) ? t('Private forum') : t('Public forum'));
unset($forums[$x]['abook_id']);
unset($forums[$x]['xchan_hash']);
unset($forums[$x]['xchan_name']);
unset($forums[$x]['xchan_url']);
unset($forums[$x]['xchan_photo_s']);
$i = $i + $r[0]['total'];
}
else {
unset($forums[$x]);
if ($r) {
$result[$forum_id]['count'] = count($r);
}
}
$result['forums']['count'] = $i;
$result['forums']['notifications'] = array_values($forums);
}
return $result;

View File

@@ -12,7 +12,6 @@ class Notifications {
function widget($arr) {
$channel = \App::get_channel();
$notifications = [];
if(local_channel()) {
@@ -35,7 +34,6 @@ class Notifications {
]
];
$notifications[] = [
'type' => 'home',
'icon' => 'house',
@@ -43,7 +41,7 @@ class Notifications {
'label' => t('Channel'),
'title' => t('Unseen channel activity'),
'viewall' => [
'url' => 'channel/' . $channel['channel_address'],
'url' => 'channel',
'label' => t('Channel stream')
],
'markall' => [
@@ -124,16 +122,17 @@ class Notifications {
]
];
$notifications[] = [
'type' => 'forums',
'icon' => 'chat-quote',
'severity' => 'secondary',
'label' => t('Forums'),
'title' => t('Unseen forums activity'),
'filter' => [
'name_label' => t('Filter by name or address')
]
];
$forums = get_forum_channels(local_channel());
foreach($forums as $forum) {
$notifications[] = [
'type' => 'forum_' . $forum['abook_id'],
'icon' => 'chat-quote',
'severity' => 'secondary',
'label' => $forum['xchan_name'],
'title' => t('Unseen forum activity')
];
}
}
if(local_channel() && is_site_admin()) {
@@ -157,11 +156,6 @@ class Notifications {
'url' => 'pubstream',
'label' => t('Public stream')
],
/*
'markall' => [
'label' => t('Mark all notifications seen')
],
*/
'filter' => [
'posts_label' => t('Conversation starters'),
'name_label' => t('Filter by name or address')
@@ -169,16 +163,13 @@ class Notifications {
];
}
$o = replace_macros(get_markup_template('notifications_widget.tpl'), [
return replace_macros(get_markup_template('notifications_widget.tpl'), [
'$notifications' => $notifications,
'$no_notifications' => t('Sorry, you have got no notifications at the moment'),
'$loading' => t('Loading'),
'$sys_only' => empty($arr['sys_only']) ? 0 : 1
]);
return $o;
}
}

View File

@@ -70,7 +70,7 @@ require_once('include/security.php');
define('PLATFORM_NAME', 'hubzilla');
define('STD_VERSION', '10.5.8');
define('STD_VERSION', '10.5.9');
define('ZOT_REVISION', '6.0');
define('DB_UPDATE_VERSION', 1264);

View File

@@ -135,7 +135,6 @@
sse_bs_active = false;
sse_partial_result = true;
sse_offset = obj[sse_type].offset;
if (sse_offset < 0) {
document.getElementById("nav-" + sse_type + "-loading").style.display = 'none';
}
@@ -297,7 +296,7 @@
});
document.addEventListener('hz:sse_setNotificationsStatus', function(e) {
sse_setNotificationsStatus(e.detail);
sse_setNotificationsStatus(e.detail, null);
});
document.addEventListener('hz:sse_bs_init', function() {
@@ -414,7 +413,6 @@
sse_bs_active = false;
sse_rmids = [];
document.getElementById("nav-" + sse_type + "-loading").style.display = 'none';
sse_offset = obj[sse_type].offset;
sse_handleNotifications(obj, replace, followup);
})
.catch(error => {
@@ -430,6 +428,7 @@
}
function sse_handleNotifications(obj, replace, followup) {
// Notice and info notifications
if (obj.notice) {
obj.notice.notifications.forEach(notification => {
@@ -447,9 +446,7 @@
return;
}
let primary_notifications = ['dm', 'home', 'intros', 'register', 'notify', 'files'];
let secondary_notifications = ['network', 'forums', 'all_events', 'pubs'];
let all_notifications = [...primary_notifications, ...secondary_notifications];
let all_notifications = Object.keys(obj);
all_notifications.forEach(type => {
if (typeof obj[type] === 'undefined') {
@@ -476,7 +473,7 @@
if (subElement) subElement.classList.remove('show');
if (buttonElement) {
buttonElement.style.display = 'none'; // Fade-out effect replaced by display none
sse_setNotificationsStatus();
sse_setNotificationsStatus(null, null);
}
}
@@ -485,24 +482,23 @@
}
});
sse_setNotificationsStatus();
sse_setNotificationsStatus(null, all_notifications);
// Load more notifications if visible notifications count becomes low
if (sse_type && sse_offset !== -1) {
let menu = document.getElementById('nav-' + sse_type + '-menu');
if (menu && menu.children.length < 15) {
sse_bs_notifications(sse_type, false, true);
if (typeof obj[sse_type] !== 'undefined') {
sse_offset = obj[sse_type].offset;
// Load more notifications if visible notifications count becomes low
if (sse_type && sse_offset !== -1) {
let menu = document.getElementById('nav-' + sse_type + '-menu');
if (menu && menu.children.length < 15) {
sse_bs_notifications(sse_type, false, true);
}
}
}
}
function sse_handleNotificationsItems(notifyType, data, replace, followup) {
// Get the template, adjust based on the notification type
let notifications_tpl = (notifyType === 'forums')
? decodeURIComponent(document.querySelector("#nav-notifications-forums-template[rel=template]").innerHTML.replace('data-src', 'src'))
: decodeURIComponent(document.querySelector("#nav-notifications-template[rel=template]").innerHTML.replace('data-src', 'src'));
let notifications_tpl = decodeURIComponent(document.querySelector("#nav-notifications-template[rel=template]").innerHTML.replace('data-src', 'src'));
let notify_menu = document.getElementById("nav-" + notifyType + "-menu");
let notify_loading = document.getElementById("nav-" + notifyType + "-loading");
let notify_count = document.getElementsByClassName(notifyType + "-update");
@@ -598,10 +594,14 @@
}
function sse_setNotificationsStatus(data) {
function sse_setNotificationsStatus(data, all_notifications) {
let primary_notifications = ['dm', 'home', 'intros', 'register', 'notify', 'files'];
let secondary_notifications = ['network', 'forums', 'all_events', 'pubs'];
let all_notifications = primary_notifications.concat(secondary_notifications);
if (!all_notifications) {
all_notifications = primary_notifications.concat(secondary_notifications);
}
let primary_available = false;
let any_available = false;
@@ -650,46 +650,17 @@
}
// Handle specific notifications if 'data' is provided
if (typeof data !== 'undefined') {
if (data) {
data.forEach(function (nmid) {
sse_rmids.push(nmid);
// Handle regular notifications
let notification = document.querySelector(`.notification[data-b64mid='${nmid}']`);
if (notification) {
let parentId = notification.parentElement.id.split('-')[1];
sse_updateNotifications(parentId, nmid);
}
// Special handling for forum notifications
let forumNotifications = document.querySelectorAll('.notification-forum');
forumNotifications.forEach(function (forumNotification) {
let fmids = decodeURIComponent(forumNotification.dataset.b64mids);
let parentId = forumNotification.parentElement.id.split('-')[1];
if (fmids.indexOf(nmid) > -1) {
let updateElem = document.querySelector(`.${parentId}-update`);
let fcount = Number(updateElem.innerText);
fcount--;
updateElem.innerText = fcount;
if (fcount < 1) {
let button = document.querySelector(`.${parentId}-button`);
button.style.display = 'none';
let subMenu = document.querySelector(`#nav-${parentId}-sub`);
if (subMenu) subMenu.classList.remove('show');
}
let countElem = forumNotification.querySelector('.bg-secondary');
let count = Number(countElem.innerText);
count--;
countElem.innerText = count;
if (count < 1) {
forumNotification.remove();
}
}
});
});
}
}
@@ -731,15 +702,6 @@
</div>
</a>
</div>
<div id="nav-notifications-forums-template" rel="template" class="d-none">
<a class="list-group-item list-group-item-action justify-content-between align-items-center d-flex notification notification-forum" href="{0}" title="{4} - {3}" data-b64mid="{7}" data-notify_id="{8}" data-thread_top="{9}" data-contact_name="{2}" data-contact_addr="{3}" data-b64mids='{12}'>
<div>
<img class="menu-img-1" data-src="{1}" loading="lazy">
<span>{2}</span>
</div>
<span class="badge bg-secondary">{10}</span>
</a>
</div>
<div id="notifications" class="border border-top-0 rounded navbar-nav collapse">
{{foreach $notifications as $notification}}
<div class="rounded-top rounded-bottom border border-start-0 border-end-0 border-bottom-0 list-group list-group-flush collapse {{$notification.type}}-button">