diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php index a2f7463dd4..0483ae009d 100644 --- a/phpBB/develop/create_schema_files.php +++ b/phpBB/develop/create_schema_files.php @@ -1299,6 +1299,7 @@ function get_schema_struct() 'COLUMNS' => array( 'item_type' => array('VCHAR:25', ''), 'item_id' => array('UINT', 0), + 'item_parent_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'unread' => array('BOOL', 1), 'time' => array('TIMESTAMP', 1), @@ -1312,8 +1313,10 @@ function get_schema_struct() 'KEYS' => array( 'item_type' => array('INDEX', 'item_type'), 'item_id' => array('INDEX', 'item_id'), + 'item_pid' => array('INDEX', 'item_parent_id'), 'user_id' => array('INDEX', 'user_id'), 'time' => array('INDEX', 'time'), + 'unread' => array('INDEX', 'unread'), ), ); diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index e5c7839894..3d3dd1f5bc 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1285,15 +1285,20 @@ function phpbb_timezone_select($user, $default = '', $truncate = false) function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $user_id = 0) { global $db, $user, $config; - global $request; + global $request, $phpbb_container; if ($mode == 'all') { if ($forum_id === false || !sizeof($forum_id)) { + // Mark all forums read (index page) + + // Mark all topic notifications read for this user + $notifications = $phpbb_container->get('notifications'); + $notifications->mark_notifications_read('topic', false, $user->data['user_id'], $post_time); + if ($config['load_db_lastread'] && $user->data['is_registered']) { - // Mark all forums read (index page) $db->sql_query('DELETE FROM ' . TOPICS_TRACK_TABLE . " WHERE user_id = {$user->data['user_id']}"); $db->sql_query('DELETE FROM ' . FORUMS_TRACK_TABLE . " WHERE user_id = {$user->data['user_id']}"); $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_lastmark = ' . time() . " WHERE user_id = {$user->data['user_id']}"); @@ -1330,6 +1335,10 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ $forum_id = array($forum_id); } + // Mark topic notifications read for this user in this forum + $notifications = $phpbb_container->get('notifications'); + $notifications->mark_notifications_read_by_parent('topic', $forum_id, $user->data['user_id'], $post_time); + // Add 0 to forums array to mark global announcements correctly // $forum_id[] = 0; @@ -1424,6 +1433,11 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ return; } + // Mark post notifications read for this user in this topic + $notifications = $phpbb_container->get('notifications'); + $notifications->mark_notifications_read_by_parent('post', $topic_id, $user->data['user_id'], $post_time); + $notifications->mark_notifications_read_by_parent('quote', $topic_id, $user->data['user_id'], $post_time); + if ($config['load_db_lastread'] && $user->data['is_registered']) { $sql = 'UPDATE ' . TOPICS_TRACK_TABLE . ' diff --git a/phpBB/includes/notifications/service.php b/phpBB/includes/notifications/service.php index 10af5b349b..8be8ae2a95 100644 --- a/phpBB/includes/notifications/service.php +++ b/phpBB/includes/notifications/service.php @@ -106,6 +106,52 @@ class phpbb_notifications_service return $notifications; } + /** + * Mark notifications read + * + * @param string $item_type item type + * @param bool|int|array $item_id Item id or array of item ids. False to mark read for all item ids + * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids + * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False) + */ + public function mark_notifications_read($item_type, $item_id, $user_id, $time = false) + { + $time = ($time) ?: time(); + + $this->get_item_type_class_name($item_type); + + $sql = 'UPDATE ' . NOTIFICATIONS_TABLE . " + SET unread = 0 + WHERE item_type = '" . $this->db->sql_escape($item_type) . "' + AND time <= " . $time . + (($item_id !== false) ? ' AND ' . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id) : '') . + (($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : ''); + $this->db->sql_query($sql); + } + + /** + * Mark notifications read from a parent identifier + * + * @param string $item_type item type + * @param bool|int|array $item_parent_id Item parent id or array of item parent ids. False to mark read for all item parent ids + * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids + * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False) + */ + public function mark_notifications_read_by_parent($item_type, $item_parent_id, $user_id, $time = false) + { + $time = ($time) ?: time(); + + $item_type_class_name = $this->get_item_type_class_name($item_type); + + $sql = 'UPDATE ' . NOTIFICATIONS_TABLE . " + SET unread = 0 + WHERE item_type = '" . $this->db->sql_escape($item_type) . "' + AND time <= " . $time . + (($item_parent_id !== false) ? ' AND ' . (is_array($item_parent_id) ? $this->db->sql_in_set('item_parent_id', $item_parent_id) : 'item_parent_id = ' . (int) $item_parent_id) : '') . + (($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : ''); + $this->db->sql_query($sql); + } + /** * Add a notification * @@ -118,9 +164,6 @@ class phpbb_notifications_service $item_id = $item_type_class_name::get_item_id($data); - // Update any existing notifications for this item - $this->update_notifications($item_type, $data); - // find out which users want to receive this type of notification $notify_users = $item_type_class_name::find_users_for_notification($this->phpbb_container, $data); @@ -250,6 +293,8 @@ class phpbb_notifications_service */ public function delete_notifications($item_type, $item_id) { + $this->get_item_type_class_name($item_type); + $sql = 'DELETE FROM ' . NOTIFICATIONS_TABLE . " WHERE item_type = '" . $this->db->sql_escape($item_type) . "' AND " . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id); diff --git a/phpBB/includes/notifications/type/base.php b/phpBB/includes/notifications/type/base.php index 47db2c4aa7..daca3b43cb 100644 --- a/phpBB/includes/notifications/type/base.php +++ b/phpBB/includes/notifications/type/base.php @@ -40,6 +40,7 @@ abstract class phpbb_notifications_type_base implements phpbb_notifications_type * Indentification data * item_type * item_id + * item_parent_id // Parent item id (ex: for topic => forum_id, for post => topic_id, etc) * user_id * unread * @@ -145,33 +146,6 @@ abstract class phpbb_notifications_type_base implements phpbb_notifications_type return $this->mark(true, $return); } - /** - * Mark this item read/unread - * - * @param bool $unread Unread (True/False) (Default: False) - * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False) - * @return string - */ - protected function mark($unread = true, $return = false) - { - $where = array( - 'item_type = ' . $this->db->sql_escape($this->item_type), - 'item_id = ' . (int) $this->item_id, - 'user_id = ' . (int) $this->user_id, - ); - $where = implode(' AND ' . $where); - - if ($return) - { - return $where; - } - - $sql = 'UPDATE ' . NOTIFICATIONS_TABLE . ' - SET unread = ' . (bool) $unread . ' - WHERE ' . $where; - $this->db->sql_query($sql); - } - /** * Function for preparing the data for insertion in an SQL query * (The service handles insertion) @@ -184,11 +158,14 @@ abstract class phpbb_notifications_type_base implements phpbb_notifications_type { // Defaults $data = array_merge(array( - 'item_type' => $this->get_item_type(), - 'time' => time(), - 'unread' => true, + 'item_id' => static::get_item_id($type_data), + 'item_type' => $this->get_item_type(), + 'item_parent_id' => static::get_item_parent_id($type_data), - 'data' => array(), + 'time' => time(), + 'unread' => true, + + 'data' => array(), ), $this->data); $data['data'] = serialize($data['data']); @@ -219,49 +196,8 @@ abstract class phpbb_notifications_type_base implements phpbb_notifications_type } /** - * Find the users who want to receive notifications (helper) - * - * @param ContainerBuilder $phpbb_container - * @param array $item_id The item_id to search for - * - * @return array + * -------------- Fall back functions ------------------- */ - protected static function _find_users_for_notification(ContainerBuilder $phpbb_container, $item_id) - { - $db = $phpbb_container->get('dbal.conn'); - - $rowset = array(); - - $sql = 'SELECT * - FROM ' . USER_NOTIFICATIONS_TABLE . " - WHERE item_type = '" . static::get_item_type() . "' - AND item_id = " . (int) $item_id; - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($rowset[$row['user_id']])) - { - $rowset[$row['user_id']] = array(); - } - - $rowset[$row['user_id']][] = $row['method']; - } - $db->sql_freeresult($result); - - return $rowset; - } - - protected function _get_avatar($user_id) - { - $user = $this->service->get_user($user_id); - - if (!function_exists('get_user_avatar')) - { - include($this->phpbb_root_path . 'includes/functions_display.' . $this->php_ext); - } - - return get_user_avatar($user['user_avatar'], $user['user_avatar_type'], $user['user_avatar_width'], $user['user_avatar_height'], $user['username'], false, 'notifications-avatar'); - } /** * Get the formatted title of this notification (fall-back) @@ -306,4 +242,86 @@ abstract class phpbb_notifications_type_base implements phpbb_notifications_type { return; } + + /** + * -------------- Helper functions ------------------- + */ + + /** + * Find the users who want to receive notifications (helper) + * + * @param ContainerBuilder $phpbb_container + * @param array $item_id The item_id to search for + * + * @return array + */ + protected static function _find_users_for_notification(ContainerBuilder $phpbb_container, $item_id) + { + $db = $phpbb_container->get('dbal.conn'); + + $rowset = array(); + + $sql = 'SELECT * + FROM ' . USER_NOTIFICATIONS_TABLE . " + WHERE item_type = '" . static::get_item_type() . "' + AND item_id = " . (int) $item_id; + $result = $db->sql_query($sql); + while ($row = $db->sql_fetchrow($result)) + { + if (!isset($rowset[$row['user_id']])) + { + $rowset[$row['user_id']] = array(); + } + + $rowset[$row['user_id']][] = $row['method']; + } + $db->sql_freeresult($result); + + return $rowset; + } + + /** + * Get avatar helper + * + * @param int $user_id + * @return string + */ + protected function _get_avatar($user_id) + { + $user = $this->service->get_user($user_id); + + if (!function_exists('get_user_avatar')) + { + include($this->phpbb_root_path . 'includes/functions_display.' . $this->php_ext); + } + + return get_user_avatar($user['user_avatar'], $user['user_avatar_type'], $user['user_avatar_width'], $user['user_avatar_height'], $user['username'], false, 'notifications-avatar'); + } + + /** + * Mark this item read/unread helper + * + * @param bool $unread Unread (True/False) (Default: False) + * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False) + * @return string + */ + protected function mark($unread = true, $return = false) + { + $where = array( + 'item_type = ' . $this->db->sql_escape($this->item_type), + 'item_id = ' . (int) $this->item_id, + 'user_id = ' . (int) $this->user_id, + ); + $where = implode(' AND ' . $where); + + if ($return) + { + return $where; + } + + $sql = 'UPDATE ' . NOTIFICATIONS_TABLE . ' + SET unread = ' . (bool) $unread . ' + WHERE ' . $where; + $this->db->sql_query($sql); + } } diff --git a/phpBB/includes/notifications/type/pm.php b/phpBB/includes/notifications/type/pm.php index 8ea1045641..89f338f3f9 100644 --- a/phpBB/includes/notifications/type/pm.php +++ b/phpBB/includes/notifications/type/pm.php @@ -44,6 +44,17 @@ class phpbb_notifications_type_pm extends phpbb_notifications_type_base return (int) $pm['msg_id']; } + /** + * Get the id of the parent + * + * @param array $pm The data from the pm + */ + public static function get_item_parent_id($pm) + { + // No parent + return 0; + } + /** * Find the users who want to receive notifications * @@ -164,8 +175,6 @@ class phpbb_notifications_type_pm extends phpbb_notifications_type_base */ public function create_insert_array($pm) { - $this->item_id = $pm['msg_id']; - $this->set_data('from_user_id', $pm['from_user_id']); $this->set_data('message_subject', $pm['message_subject']); diff --git a/phpBB/includes/notifications/type/post.php b/phpBB/includes/notifications/type/post.php index d5759111cf..324a40888d 100644 --- a/phpBB/includes/notifications/type/post.php +++ b/phpBB/includes/notifications/type/post.php @@ -35,7 +35,7 @@ class phpbb_notifications_type_post extends phpbb_notifications_type_base } /** - * Get the id of the + * Get the id of the item * * @param array $post The data from the post */ @@ -44,6 +44,16 @@ class phpbb_notifications_type_post extends phpbb_notifications_type_base return (int) $post['post_id']; } + /** + * Get the id of the parent + * + * @param array $post The data from the post + */ + public static function get_item_parent_id($post) + { + return (int) $post['topic_id']; + } + /** * Find the users who want to receive notifications * @@ -197,10 +207,6 @@ class phpbb_notifications_type_post extends phpbb_notifications_type_base */ public function create_insert_array($post) { - $this->item_id = $post['post_id']; - - $this->set_data('topic_id', $post['topic_id']); - $this->set_data('poster_id', $post['poster_id']); $this->set_data('topic_title', $post['topic_title']); diff --git a/phpBB/includes/notifications/type/quote.php b/phpBB/includes/notifications/type/quote.php index e17769acea..11186f3685 100644 --- a/phpBB/includes/notifications/type/quote.php +++ b/phpBB/includes/notifications/type/quote.php @@ -183,8 +183,6 @@ class phpbb_notifications_type_quote extends phpbb_notifications_type_post $add_notifications[$user_id] = $notifications[$user_id]; } - var_dump($old_notifications, $notifications, $remove_notifications, $add_notifications); - // Add the necessary notifications $service->add_notifications_for_users(self::get_item_type(), $post, $add_notifications); diff --git a/phpBB/includes/notifications/type/topic.php b/phpBB/includes/notifications/type/topic.php index cb7bfdbb8f..0fce65a0cf 100644 --- a/phpBB/includes/notifications/type/topic.php +++ b/phpBB/includes/notifications/type/topic.php @@ -35,7 +35,7 @@ class phpbb_notifications_type_topic extends phpbb_notifications_type_base } /** - * Get the id of the + * Get the id of the item * * @param array $post The data from the post */ @@ -44,6 +44,16 @@ class phpbb_notifications_type_topic extends phpbb_notifications_type_base return (int) $post['topic_id']; } + /** + * Get the id of the parent + * + * @param array $post The data from the post + */ + public static function get_item_parent_id($post) + { + return (int) $post['forum_id']; + } + /** * Find the users who want to receive notifications * @@ -166,7 +176,7 @@ class phpbb_notifications_type_topic extends phpbb_notifications_type_base */ public function get_url() { - return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "f={$this->get_data('forum_id')}&t={$this->item_id}"); + return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "f={$this->item_parent_id}&t={$this->item_id}"); } /** @@ -176,7 +186,7 @@ class phpbb_notifications_type_topic extends phpbb_notifications_type_base */ public function get_full_url() { - return generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_id}"; + return generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->item_parent_id}&t={$this->item_id}"; } /** @@ -199,8 +209,6 @@ class phpbb_notifications_type_topic extends phpbb_notifications_type_base */ public function create_insert_array($post) { - $this->item_id = $post['topic_id']; - $this->set_data('poster_id', $post['poster_id']); $this->set_data('topic_title', $post['topic_title']); @@ -209,8 +217,6 @@ class phpbb_notifications_type_topic extends phpbb_notifications_type_base $this->set_data('forum_name', $post['forum_name']); - $this->set_data('forum_id', $post['forum_id']); - return parent::create_insert_array($post); } } diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index c3c2da4451..a79c04f8df 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -1109,6 +1109,7 @@ function database_update_info() 'COLUMNS' => array( 'item_type' => array('VCHAR:25', ''), 'item_id' => array('UINT', 0), + 'item_parent_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'unread' => array('BOOL', 1), 'time' => array('TIMESTAMP', 1), @@ -1122,8 +1123,10 @@ function database_update_info() 'KEYS' => array( 'item_type' => array('INDEX', 'item_type'), 'item_id' => array('INDEX', 'item_id'), + 'item_pid' => array('INDEX', 'item_parent_id'), 'user_id' => array('INDEX', 'user_id'), 'time' => array('INDEX', 'time'), + 'unread' => array('INDEX', 'unread'), ), ), USER_NOTIFICATIONS_TABLE => array( diff --git a/phpBB/styles/prosilver/template/overall_header.html b/phpBB/styles/prosilver/template/overall_header.html index 1695f8d03a..8c0cc562ae 100644 --- a/phpBB/styles/prosilver/template/overall_header.html +++ b/phpBB/styles/prosilver/template/overall_header.html @@ -136,7 +136,7 @@