Skip to content

Commit

Permalink
Merge pull request #3796 from Spuds/MentionsTab
Browse files Browse the repository at this point in the history
Mark notifications as read when you read unread messages
  • Loading branch information
Spuds authored Apr 29, 2024
2 parents 9758e91 + 8e3750d commit 4c94217
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 42 deletions.
87 changes: 60 additions & 27 deletions sources/ElkArte/Controller/Display.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,11 @@ public function action_display()
// The start isn't a number; it's information about what to do, where to go.
$this->makeStartAdjustments($total_visible_posts);

// Censor the title...
// Censor the subject...
$this->topicinfo['subject'] = censor($this->topicinfo['subject']);

// Allow addons access to the topicinfo array
call_integration_hook('integrate_display_topic', array($this->topicinfo));
call_integration_hook('integrate_display_topic', [$this->topicinfo]);

// If all is set, figure out what needs to be done
$can_show_all = $this->getCanShowAll($total_visible_posts);
Expand Down Expand Up @@ -159,7 +159,7 @@ public function action_display()
'offset' => $limit,
];

// Get each post and poster in this topic.
// Get each post and poster on this topic page.
$topic_details = getTopicsPostsAndPoster($this->topicinfo['id_topic'], $limit_settings, $ascending);
$messages = $topic_details['messages'];

Expand All @@ -175,14 +175,17 @@ public function action_display()
$context['first_message'] = 0;
$context['first_new_message'] = false;

call_integration_hook('integrate_display_message_list', array(&$messages, &$all_posters));
call_integration_hook('integrate_display_message_list', [&$messages, &$all_posters]);

// If there _are_ messages here... (probably an error otherwise :!)
if (!empty($messages))
{
// Mark the board as read or not ... calls updateReadNotificationsFor() sets $context['is_marked_notify']
$this->markRead($messages, $board);

// Mark notifications for this member and first seen messages
$this->markNotificationsRead($messages);

$msg_parameters = [
'message_list' => $messages,
'new_from' => $this->topicinfo['new_from'],
Expand Down Expand Up @@ -711,6 +714,34 @@ public function warnOldTopic()
return false;
}

/**
* Marks notifications read for specified messages
*
* @param array $messages An array of message ids
* @return void
*/
private function markNotificationsRead($messages)
{
global $modSettings;

$mark_at_msg = max($messages);
if ($mark_at_msg >= $this->topicinfo['id_last_msg'])
{
$mark_at_msg = $modSettings['maxMsgID'];
}

// If there are new messages "in view", lets mark any notification for them as read
if ($mark_at_msg >= $this->topicinfo['new_from'])
{
require_once(SUBSDIR . '/Mentions.subs.php');
$filterMessages = array_filter($messages, static function ($element) use ($mark_at_msg) {
return $element >= $mark_at_msg;
});

markNotificationsRead($filterMessages);
}
}

/**
* Keeps track of where the user is in reading this topic.
*
Expand All @@ -721,37 +752,39 @@ private function markRead($messages, $board)
{
global $modSettings;

// Guests can't mark topics read or for notifications, just can't sorry.
if ($this->user->is_guest === false && !empty($messages))
// Guests can't mark topics read or for notifications, just can't, sorry.
if ($this->user->is_guest || empty($messages))
{
$boardseen = isset($this->_req->query->boardseen);

$mark_at_msg = max($messages);
if ($mark_at_msg >= $this->topicinfo['id_last_msg'])
{
$mark_at_msg = $modSettings['maxMsgID'];
}
return;
}

if ($mark_at_msg >= $this->topicinfo['new_from'])
{
markTopicsRead(array($this->user->id, $this->topicinfo['id_topic'], $mark_at_msg, $this->topicinfo['unwatched']), $this->topicinfo['new_from'] !== 0);
$numNewTopics = getUnreadCountSince($board, empty($_SESSION['id_msg_last_visit']) ? 0 : $_SESSION['id_msg_last_visit']);
$boardseen = isset($this->_req->query->boardseen);

if (empty($numNewTopics))
{
$boardseen = true;
}
}
$mark_at_msg = max($messages);
if ($mark_at_msg >= $this->topicinfo['id_last_msg'])
{
$mark_at_msg = $modSettings['maxMsgID'];
}

updateReadNotificationsFor($this->topicinfo['id_topic'], $board);
if ($mark_at_msg >= $this->topicinfo['new_from'])
{
markTopicsRead([$this->user->id, $this->topicinfo['id_topic'], $mark_at_msg, $this->topicinfo['unwatched']], $this->topicinfo['new_from'] !== 0);
$numNewTopics = getUnreadCountSince($board, empty($_SESSION['id_msg_last_visit']) ? 0 : $_SESSION['id_msg_last_visit']);

// Mark board as seen if we came using last post link from BoardIndex. (or other places...)
if ($boardseen)
if (empty($numNewTopics))
{
require_once(SUBSDIR . '/Boards.subs.php');
markBoardsRead($board, false, false);
$boardseen = true;
}
}

updateReadNotificationsFor($this->topicinfo['id_topic'], $board);

// Mark board as seen if we came using last post link from BoardIndex. (or other places...)
if ($boardseen)
{
require_once(SUBSDIR . '/Boards.subs.php');
markBoardsRead($board, false, false);
}
}

/**
Expand Down
14 changes: 4 additions & 10 deletions sources/ElkArte/Mentions/Mentioning.php
Original file line number Diff line number Diff line change
Expand Up @@ -297,22 +297,16 @@ protected function _getAccessible($mention_ids, $action)
* - note that delete is a "soft-delete" because otherwise anyway we have to remember
* - when a user was already mentioned for a certain message (e.g. in case of editing)
*
* @param int|int[] $id_mentions the mention id in the db
* @param int|int[] $id_mentions the mention(s) id in the db
* @param string $status status to update, 'new', 'read', 'deleted', 'unapproved'
* @return bool if successfully changed or not
* @package Mentions
*/
protected function _changeStatus($id_mentions, $status = 'read')
{
$success = $this->_db->query('', '
UPDATE {db_prefix}log_mentions
SET status = {int:status}
WHERE id_mention IN ({array_int:id_mentions})',
[
'id_mentions' => (array) $id_mentions,
'status' => $this->_known_status[$status],
]
)->affected_rows() !== 0;
require_once(SUBSDIR . '/Mentions.subs.php');

$success = changeStatus($id_mentions, $this->user->id, $this->_known_status[$status], false);

// Update the top level mentions count
if ($success)
Expand Down
118 changes: 113 additions & 5 deletions sources/subs/Mentions.subs.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ function toggleMentionsApproval($msgs, $approved)
// Update the mentions menu count for the members that have this message
$status = $approved ? 0 : 3;
$db->fetchQuery('
SELECT id_member, status
SELECT
id_member, status
FROM {db_prefix}log_mentions
WHERE id_target IN ({array_int:messages})',
array(
Expand Down Expand Up @@ -437,11 +438,11 @@ function getNewMentions($id_member, $timestamp)
* Get the available mention types for a user.
*
* @param int|null $user The user ID. If null, User::$info->id will be used.
* @param string $type The type of mentions. user will return only those that the user has enabled and set
* as notification. If not user, returns the system level enabled mentions.
* @param string $type The type of mentions. "user" will return only those that the user has enabled and set
* as on site notification.
*
* By default, will filter out notification types with a method set to none, e.g. the user had disable that
* type of mention. Use type=all to return everything, or type=notification to return only those
* By default, will filter out notification types with a method set to none, e.g. the user has disabled that
* type of mention. Use type "system" to return everything, or type "user" to return only those
* that they want on-site notifications.
*
* @return array The available mention types.
Expand Down Expand Up @@ -487,3 +488,110 @@ function getMentionTypes($user, $type = 'user')
sort($enabled);
return $enabled;
}

/**
* Marks a set of notifications as read.
*
* Intended to be called when viewing a topic page.
*
* @param array $messages
*/
function markNotificationsRead($messages)
{
// Guests can't mark notifications
if (User::$info->is_guest || empty($messages))
{
return;
}

// These are the types associated with messages (where the id_target is a msg_id)
$mentionTypes = ['mentionmem', 'likemsg', 'rlikemsg', 'quotedmem', 'watchedtopic', 'watchedboard'];
$messages = is_array($messages) ? $messages : [$messages];
$changes = [];

// Find unread notifications for this group of messages for this member
$db = database();
$db->fetchQuery('
SELECT
id_mention
FROM {db_prefix}log_mentions
WHERE status = {int:status}
AND id_member = {int:member}
AND id_target IN ({array_int:targets})
AND mention_type IN ({array_string:mention_types})',
[
'status' => 0,
'member' => User::$info->id,
'targets' => $messages,
'mention_types' => $mentionTypes,
]
)->fetch_callback(
function ($row) use (&$changes) {
$changes[] = (int) $row['id_mention'];
});

if (!empty($changes))
{
changeStatus(array_unique($changes), User::$info->id);
}
}

/**
* Change the status of mentions
*
* Updates the status of mentions in the database. Also updates the mentions count for the member.
*
* - Can be used to mark as read, new, deleted, etc a group of mention id's
* - Note that delete is a "soft-delete" because otherwise anyway we have to remember
* - When a user was already mentioned for a certain message (e.g. in case of editing)
*
* @param int|array $id_mentions The id(s) of the mentions to update
* @param int $member_id The id of the member
* @param int $status The new status for the mentions (default: 1)
* @param bool $update Whether to update the mentions count (default: true)
*
* @return bool Returns true if the update was successful, false otherwise
*/
function changeStatus($id_mentions, $member_id, $status = 1, $update = true)
{
$db = database();

$id_mentions = is_array($id_mentions) ? $id_mentions : [$id_mentions];
$status = $status ?? 1;

$success = $db->query('', '
UPDATE {db_prefix}log_mentions
SET status = {int:status}
WHERE id_mention IN ({array_int:id_mentions})',
[
'id_mentions' => $id_mentions,
'status' => $status,
]
)->affected_rows() !== 0;

// Update the mentions count
if ($success && $update)
{
$number = count($id_mentions);
require_once(SUBSDIR . '/Members.subs.php');

// Increase the count by 1
if ($number === 1 && $status === 0)
{
updateMemberData($member_id, ['mentions' => '+']);
return true;
}

// Mark as read we decrease the count by 1
if ($number === 1 && $status === 1)
{
updateMemberData($member_id, ['mentions' => '-']);
return true;
}

// A full recount is required
countUserMentions(false, '', $member_id);
}

return $success;
}

0 comments on commit 4c94217

Please sign in to comment.